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 Thu Apr 12 12:11:39 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.) @@ -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 @@ -1725,12 +1729,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 +1879,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 +2364,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 +2408,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 +2434,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 +2521,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 +2709,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 Tue Apr 17 17:23:06 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 @@ -1616,12 +1646,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 @@ -2110,7 +2140,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 @@ -2821,14 +2850,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 +3015,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 +3532,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 +4324,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 +4337,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 +4351,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 +4855,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 +4940,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 +5108,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 @@ -8078,6 +8111,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 +8209,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 +8237,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 +8360,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 +8423,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 +10170,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 +10275,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 +10296,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 +10361,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 +10380,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 +10390,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 +10565,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 +11002,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 +11248,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 +11831,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 +11915,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 +11947,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 +12202,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 +12391,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 +12403,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 +12414,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 +12424,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 @@ -13742,17 +13946,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 +14006,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 +14484,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 +14692,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 +14882,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 +14896,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 @@ -16523,6 +16763,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 +16861,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 +16947,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 +16968,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 +17004,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 +17117,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 +17202,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 +17210,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 +17278,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 +17663,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 +17691,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 +17708,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 +17835,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/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/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 ...> +<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 <sfr@linuxcare.com.au> + Stephen Rothwell <sfr@canb.auug.org.au> 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/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. + <bool>: 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/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/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/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/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 <ncorbic@sangoma.com> -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 <mike.mclagan@linux.org> 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 <ncorbic@sangoma.com> -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 <hex-address>" 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 + <run silo in the usual way> + + 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 <vmguestname>"). + 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 <rbh00@utsglobal.com> 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 <main+0xc> + 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 <test>: +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>: +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 <test> + 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 <victim program or object file> > <victims debug listing > + + +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 <sys_sigsuspend+0x2e> + 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<pid> 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<return> +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 <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2> +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 <breakpoint number> + +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 <enter> 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 <address> +To debug a particular function try +TR I R <function address range> +TR I on its own will single step. +TR I DATA <MNEMONIC> <OPTIONAL RANGE> 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 <INTO OR FROM> 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 <address range> 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 <range> +To make VM display a message each time it hits a particular address & continue try +D I<range> will disassemble/display a range of instructions. +ST addr 32 bit word will store a 32 bit aligned address +D T<range> will display the EBCDIC in an address ( if you are that way inclined ) +D R<range> 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 <command name> 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 <address range>. +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 <program to be debugged> | grep main +To get the address of main in the program. +tr i pswa <address of main> +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 <CR13's value> 0.7fffffff +e.g. +TR I R STD 8F32E1FF 0.7fffffff +Another very useful variation is +TR STORE INTO STD <CR13's value> <address range> + + + + +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 <range or value> 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 <Driver open address> +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 <Driver open address> 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 <Optional value or range> +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 <desired cpu no> + +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 <cpu number> 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 <stdio.h> + +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<argc;cnt1++) + { + len=strlen(argv[cnt1]); + for(cnt2=0;cnt2<len;cnt2++) + { + c=argv[cnt1][cnt2]; + if(c>='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 <command> from CMS. +detaching devices +DET <devno range> +ATT <devno range> <guest> +attach a device to guest * for your own guest +READY <devno> cause VM to issue a fake interrupt. + +The VARY command is normally only available to VM administrators. +VARY ON PATH <path> TO <devno range> +VARY OFF PATH <PATH> FROM <devno range> +This is used to switch on or off channel paths to devices. + +Q CHPID <channel path ID> +This displays state of devices using this channel path +D SCHIB <subchannel> +This displays the subchannel information SCHIB block for the device. +this I believe is also only available to administrators. +DEFINE CTC <devno> +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> <subchannel> <number blocks> +blocksize is commonly 4096 for linux. +Formatting it +format <subchannel> <driver letter e.g. x> (blksize <blocksize> + +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 <victim program> <optional corefile> + +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 <variable>=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 <name> <list of commands> 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 <function> +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 <TAB> & 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/<number lines to disassemble>xi <address> +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 <gdb's pid> +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/<pid> +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 <network device> +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 <broadcast_addr> 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 <scriptname> +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 <scriptname> runs the perlscript in a fully intercative debugger +<like gdb>. +Type 'h' in the debugger for help. + +for debugging java type +jdb <filename> 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 <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>. +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 <linux/module.h> +#include <asm/debug.h> + +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 <linux/module.h> +#include <asm/debug.h> + +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 <asm/debug.h> + +#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=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2> 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=<io>,<irq>,<dma>,<dma2>" 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 Thu Apr 12 12:11:39 2001 @@ -106,6 +106,13 @@ L: linux-net@vger.kernel.org S: Maintained +ACI MIXER DRIVER +P: Robert Siemer +M: Robert.Siemer@gmx.de +L: linux-sound@vger.kernel.org +W: http://www.uni-karlsruhe.de/~Robert.Siemer/Private/ +S: Maintained + ACPI P: Andy Grover M: andrew.grover@intel.com @@ -141,9 +148,9 @@ APM DRIVER P: Stephen Rothwell -M: apm@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-laptop@vger.kernel.org -W: http://linuxcare.com.au/apm/ +W: http://www.canb.auug.org.au/~sfr/ S: Supported APPLETALK NETWORK LAYER @@ -293,6 +300,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 +382,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 +412,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 +510,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 +561,7 @@ HIPPI P: Jes Sorensen -M: Jes.Sorensen@cern.ch +M: jes@linuxcare.com L: linux-hippi@sunsite.auc.dk S: Maintained @@ -600,7 +626,14 @@ W: http://www.kernel.dk S: Maintained -IDE/ATAPI TAPE/FLOPPY DRIVERS +IDE/ATAPI FLOPPY DRIVERS +P: Paul Bristow +M: Paul Bristow <paul@paulbristow.net> +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 <gadio@netvision.net.il> L: linux-kernel@vger.kernel.org @@ -750,14 +783,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 +808,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 +820,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 +876,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 +947,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 @@ -997,7 +1041,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 +1081,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 +1107,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 +1233,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 +1421,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 +1494,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 +1521,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 13 20:26:46 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 3 -EXTRAVERSION = +SUBLEVEL = 4 +EXTRAVERSION =-pre4 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 <URL:ftp://ftp.sai.msu.su/pub/Linux/ver_linux> 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: <one line diff -u --recursive --new-file v2.4.3/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.3/linux/arch/alpha/config.in Fri Dec 29 14:07:19 2000 +++ linux/arch/alpha/config.in Tue Apr 17 17:19:24 2001 @@ -5,6 +5,8 @@ define_bool CONFIG_ALPHA y define_bool CONFIG_UID16 n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n mainmenu_name "Kernel configuration of Linux for Alpha machines" diff -u --recursive --new-file v2.4.3/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.4.3/linux/arch/alpha/kernel/alpha_ksyms.c Fri Mar 2 11:15:47 2001 +++ linux/arch/alpha/kernel/alpha_ksyms.c Fri Apr 13 20:26:06 2001 @@ -190,7 +190,6 @@ EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(flush_tlb_all); EXPORT_SYMBOL(flush_tlb_mm); -EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); diff -u --recursive --new-file v2.4.3/linux/arch/alpha/kernel/semaphore.c linux/arch/alpha/kernel/semaphore.c --- v2.4.3/linux/arch/alpha/kernel/semaphore.c Sun Nov 12 19:31:11 2000 +++ linux/arch/alpha/kernel/semaphore.c Tue Apr 17 17:19:24 2001 @@ -263,185 +263,3 @@ #endif __up(sem); } - - -/* - * RW Semaphores - */ - -void -__down_read_failed(struct rw_semaphore *sem, int count) -{ - DECLARE_WAITQUEUE(wait, current); - - retry_down: - if (count < 0) { - /* Waiting on multiple readers and/or writers. */ - - /* Undo the acquisition we started in down_read. */ - atomic_inc(&sem->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 <linux/config.h> + + /* 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 <aschulz@netwinder.org> * * 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 <linux/linkage.h> #include <asm/assembler.h> .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 <aschulz@netwinder.org> * * This file is used to get some basic information * about the memory layout of the shark we are running @@ -11,6 +11,7 @@ #include <linux/kernel.h> +#include <linux/types.h> #include <asm/setup.h> #include <asm/page.h> @@ -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 <asm/mach/arch.h> #include <asm/hardware/dec21285.h> -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 <linux/config.h> #include <linux/linkage.h> #include <asm/hardware.h> -#include <asm/hardware/dec21285.h> .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 <asm/hardware/dec21285.h> + #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 <asm/hardware/serial_amba.h> - .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 <asm/hardware/clps7111.h> + + .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 <linux/mm.h> #include <linux/slab.h> #include <linux/proc_fs.h> +#include <linux/notifier.h> #include <linux/init.h> #include <asm/dma.h> @@ -46,6 +47,7 @@ #include <asm/irq.h> #include <asm/pgalloc.h> #include <asm/mmu_context.h> +#include <asm/mach/irq.h> #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 <asm/hardware/clps7111.h> .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 <linux/module.h> +#include <linux/types.h> + +#include <asm/io.h> + +/* + * 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 <linux/ptrace.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <asm/mach/irq.h> + +/* + * Get architecture specific interrupt handlers + * and interrupt initialisation. + */ +#include <asm/arch/irq.h> + +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 <linux/smp.h> #include <linux/init.h> -#include <asm/hardware.h> -#include <asm/io.h> +#include <asm/irq.h> #include <asm/system.h> +#include <asm/mach/irq.h> + +#include <asm/arch/irq.h> /* 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 <asm/arch/irq.h> +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 <linux/module.h> -#include <linux/spinlock.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/leds.h> -#include <asm/system.h> -#include <asm/mach-types.h> - -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 Tue Apr 17 17:19:24 2001 @@ -165,321 +165,3 @@ spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } - -struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->read_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!sem->write_bias_granted) - schedule(); - } - - remove_wait_queue(&sem->write_bias_wait, &wait); - tsk->state = TASK_RUNNING; - - /* if the lock is currently unbiased, awaken the sleepers - * FIXME: this wakes up the readers early in a bit of a - * stampede -> bad! - */ - if (atomic_read(&sem->count) >= 0) - wake_up(&sem->wait); - - return sem; -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* this takes care of granting the lock */ - __up_op_read(sem, __rwsem_wake); - - add_wait_queue(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -/* Wait for the lock to become unbiased. Since we're - * a writer, we'll make ourselves exclusive. - */ -struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* this takes care of granting the lock */ - __up_op_write(sem, __rwsem_wake); - - add_wait_queue_exclusive(&sem->wait, &wait); - - while (atomic_read(&sem->count) < 0) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to acquire or bias the lock */ - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; - - return sem; -} - -/* Called when someone has done an up that transitioned from - * negative to non-negative, meaning that the lock has been - * granted to whomever owned the bias. - */ -struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) -{ - if (xchg(&sem->read_bias_granted, 1)) - BUG(); - wake_up(&sem->wait); - return sem; -} - -struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) -{ - if (xchg(&sem->write_bias_granted, 1)) - BUG(); - wake_up(&sem->write_bias_wait); - return sem; -} - -/* - * The semaphore operations have a special calling sequence that - * allow us to do a simpler in-line version of them. These routines - * need to convert that sequence back into the C sequence when - * there is contention on the semaphore. - * - * ip contains the semaphore pointer on entry. Save the C-clobbered - * registers (r0 to r3 and lr), but not ip, as we use it as a return - * value in some cases.. - */ -#ifdef CONFIG_CPU_26 -asm(" .section .text.lock, \"ax\" - .align 5 - .globl __down_failed -__down_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __down_interruptible_failed -__down_interruptible_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_interruptible - mov ip, r0 - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __down_trylock_failed -__down_trylock_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_trylock - mov ip, r0 - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __up_wakeup -__up_wakeup: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __up - ldmfd sp!, {r0 - r3, pc}^ - - .align 5 - .globl __down_read_failed -__down_read_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_read_failed_biased - ldmfd sp!, {r0 - r3, pc}^ -2: bl down_read_failed - mov r1, pc - orr r2, r1, # - teqp r2, #0 - - ldr r3, [r0] - subs r3, r3, #1 - str r3, [r0] - ldmplfd sp!, {r0 - r3, pc}^ - orrcs r1, r1, #0x20000000 @ Set carry - teqp r1, #0 - bcc 2b - b 1b - - .align 5 - .globl __down_write_failed -__down_write_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_write_failed_biased - ldmfd sp!, {r0 - r3, pc}^ -2: bl down_write_failed - mov r1, pc - orr r2, r1, #128 - teqp r2, #0 - - ldr r3, [r0] - subs r3, r3, #"RW_LOCK_BIAS_STR" - str r3, [r0] - ldmeqfd sp!, {r0 - r3, pc}^ - orrcs r1, r1, #0x20000000 @ Set carry - teqp r1, #0 - bcc 2b - b 1b - - .align 5 - .globl __rwsem_wake -__rwsem_wake: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - beq 1f - bl rwsem_wake_readers - ldmfd sp!, {r0 - r3, pc}^ -1: bl rwsem_wake_writer - ldmfd sp!, {r0 - r3, pc}^ - - .previous - "); - -#else -/* 32 bit version */ -asm(" .section .text.lock, \"ax\" - .align 5 - .globl __down_failed -__down_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __down_interruptible_failed -__down_interruptible_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_interruptible - mov ip, r0 - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __down_trylock_failed -__down_trylock_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __down_trylock - mov ip, r0 - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __up_wakeup -__up_wakeup: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bl __up - ldmfd sp!, {r0 - r3, pc} - - .align 5 - .globl __down_read_failed -__down_read_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_read_failed_biased - ldmfd sp!, {r0 - r3, pc} -2: bl down_read_failed - mrs r1, cpsr - orr r2, r1, #128 - msr cpsr_c, r2 - ldr r3, [r0] - subs r3, r3, #1 - str r3, [r0] - msr cpsr_c, r1 - ldmplfd sp!, {r0 - r3, pc} - bcc 2b - b 1b - - .align 5 - .globl __down_write_failed -__down_write_failed: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - bcc 1f -1: bl down_write_failed_biased - ldmfd sp!, {r0 - r3, pc} -2: bl down_write_failed - mrs r1, cpsr - orr r2, r1, #128 - msr cpsr_c, r2 - ldr r3, [r0] - subs r3, r3, #"RW_LOCK_BIAS_STR" - str r3, [r0] - msr cpsr_c, r1 - ldmeqfd sp!, {r0 - r3, pc} - bcc 2b - b 1b - - .align 5 - .globl __rwsem_wake -__rwsem_wake: - stmfd sp!, {r0 - r3, lr} - mov r0, ip - beq 1f - bl rwsem_wake_readers - ldmfd sp!, {r0 - r3, pc} -1: bl rwsem_wake_writer - ldmfd sp!, {r0 - r3, pc} - - .previous - "); - -#endif diff -u --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 Thu Apr 12 12:20:31 2001 @@ -26,6 +26,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <asm/mach/irq.h> #ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) @@ -35,10 +36,21 @@ #define CONFIG_CMDLINE "" #endif +#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) +char fpe_type[8]; + +static int __init fpe_setup(char *line) +{ + memcpy(fpe_type, line, 8); + return 1; +} + +__setup("fpe=", fpe_setup); +#endif + extern void paging_init(struct meminfo *, struct machine_desc *desc); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); -extern void disable_hlt(void); extern unsigned long memparse(char *ptr, char **retptr); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; @@ -71,9 +83,10 @@ char elf_platform[ELF_PLATFORM_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; +static struct meminfo meminfo __initdata = { 0, }; static struct proc_info_item proc_info; static const char *machine_name; -static char command_line[COMMAND_LINE_SIZE] = { 0, }; +static char command_line[COMMAND_LINE_SIZE]; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; @@ -306,71 +319,222 @@ request_resource(&ioport_resource, &lp2); } +/* + * Tag parsing. + * + * This is the new way of passing data to the kernel at boot time. Rather + * than passing a fixed inflexible structure to the kernel, we pass a list + * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE + * tag for the list to be recognised (to distinguish the tagged list from + * a param_struct). The list is terminated with a zero-length tag (this tag + * is not parsed in any way). + */ +static int __init parse_tag_core(const struct tag *tag) +{ + if ((tag->u.core.flags & 1) == 0) + root_mountflags &= ~MS_RDONLY; + ROOT_DEV = to_kdev_t(tag->u.core.rootdev); + return 0; +} + +static int __init parse_tag_mem32(const struct tag *tag) +{ + if (meminfo.nr_banks >= NR_BANKS) { + printk(KERN_WARNING + "Ignoring memory bank 0x%08x size %dKB\n", + tag->u.mem.start, tag->u.mem.size / 1024); + return -EINVAL; + } + meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; + meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; + meminfo.bank[meminfo.nr_banks].node = 0; + meminfo.nr_banks += 1; + + return 0; +} + +static int __init parse_tag_videotext(const struct tag *tag) +{ + screen_info.orig_x = tag->u.videotext.x; + screen_info.orig_y = tag->u.videotext.y; + screen_info.orig_video_page = tag->u.videotext.video_page; + screen_info.orig_video_mode = tag->u.videotext.video_mode; + screen_info.orig_video_cols = tag->u.videotext.video_cols; + screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; + screen_info.orig_video_lines = tag->u.videotext.video_lines; + screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; + screen_info.orig_video_points = tag->u.videotext.video_points; + return 0; +} + +static int __init parse_tag_ramdisk(const struct tag *tag) +{ + setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, + (tag->u.ramdisk.flags & 2) == 0, + tag->u.ramdisk.start, tag->u.ramdisk.size); + return 0; +} + +static int __init parse_tag_initrd(const struct tag *tag) +{ + setup_initrd(tag->u.initrd.start, tag->u.initrd.size); + return 0; +} + +static int __init parse_tag_serialnr(const struct tag *tag) +{ + system_serial_low = tag->u.serialnr.low; + system_serial_high = tag->u.serialnr.high; + return 0; +} + +static int __init parse_tag_revision(const struct tag *tag) +{ + system_rev = tag->u.revision.rev; + return 0; +} + +static int __init parse_tag_cmdline(const struct tag *tag) +{ + strncpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + return 0; +} + +/* + * This is the core tag table; these are the tags + * that we recognise for any machine type. + */ +static const struct tagtable core_tagtable[] __init = { + { ATAG_CORE, parse_tag_core }, + { ATAG_MEM, parse_tag_mem32 }, + { ATAG_VIDEOTEXT, parse_tag_videotext }, + { ATAG_RAMDISK, parse_tag_ramdisk }, + { ATAG_INITRD, parse_tag_initrd }, + { ATAG_SERIAL, parse_tag_serialnr }, + { ATAG_REVISION, parse_tag_revision }, + { ATAG_CMDLINE, parse_tag_cmdline } +}; + +/* + * Scan one tag table for this tag, and call its parse function. + */ +static int __init +parse_tag(const struct tagtable *tbl, int size, const struct tag *t) +{ + int i; + + for (i = 0; i < size; i++, tbl++) + if (t->hdr.tag == tbl->tag) { + tbl->parse(t); + break; + } + + return i < size; +} + +/* + * Parse all tags in the list, checking both the global and architecture + * specific tag tables. + */ +static void __init +parse_tags(const struct tagtable *tbl, int size, const struct tag *t) +{ + /* + * The tag list is terminated with a zero-sized tag. Size is + * defined to be in units of 32-bit quantities. + */ + for (; t->hdr.size; t = (struct tag *)((u32 *)t + t->hdr.size)) { + if (parse_tag(core_tagtable, ARRAY_SIZE(core_tagtable), t)) + continue; + + if (tbl && parse_tag(tbl, size, t)) + continue; + + printk(KERN_WARNING + "Ignoring unrecognised tag 0x%08x\n", t->hdr.tag); + } +} + +static void __init parse_params(struct param_struct *params) +{ + if (params->u1.s.page_size != PAGE_SIZE) { + printk(KERN_WARNING "Warning: bad configuration page, " + "trying to continue\n"); + return; + } + + ROOT_DEV = to_kdev_t(params->u1.s.rootdev); + system_rev = params->u1.s.system_rev; + system_serial_low = params->u1.s.system_serial_low; + system_serial_high = params->u1.s.system_serial_high; + + if (params->u1.s.mem_fclk_21285 > 0) + mem_fclk_21285 = params->u1.s.mem_fclk_21285; + + setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, + (params->u1.s.flags & FLAG_RDPROMPT) == 0, + params->u1.s.rd_start, + params->u1.s.ramdisk_size); + + setup_initrd(params->u1.s.initrd_start, + params->u1.s.initrd_size); + + if (!(params->u1.s.flags & FLAG_READONLY)) + root_mountflags &= ~MS_RDONLY; + + strncpy(default_command_line, params->commandline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + if (meminfo.nr_banks == 0) { + meminfo.nr_banks = 1; + meminfo.bank[0].start = PHYS_OFFSET; + meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; + } +} + void __init setup_arch(char **cmdline_p) { struct param_struct *params = NULL; struct machine_desc *mdesc; - struct meminfo meminfo; char *from = default_command_line; - memset(&meminfo, 0, sizeof(meminfo)); - - setup_processor(); - ROOT_DEV = MKDEV(0, 255); + setup_processor(); mdesc = setup_architecture(machine_arch_type); machine_name = mdesc->name; - if (mdesc->broken_hlt) - disable_hlt(); - if (mdesc->soft_reboot) reboot_setup("s"); if (mdesc->param_offset) params = phys_to_virt(mdesc->param_offset); + /* + * Do the machine-specific fixups before we parse the + * parameters or tags. + */ if (mdesc->fixup) mdesc->fixup(mdesc, params, &from, &meminfo); - if (params && params->u1.s.page_size != PAGE_SIZE) { - printk(KERN_WARNING "Warning: bad configuration page, " - "trying to continue\n"); - params = NULL; - } - if (params) { - ROOT_DEV = to_kdev_t(params->u1.s.rootdev); - system_rev = params->u1.s.system_rev; - system_serial_low = params->u1.s.system_serial_low; - system_serial_high = params->u1.s.system_serial_high; - - if (params->u1.s.mem_fclk_21285 > 0) - mem_fclk_21285 = params->u1.s.mem_fclk_21285; - - setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, - (params->u1.s.flags & FLAG_RDPROMPT) == 0, - params->u1.s.rd_start, - params->u1.s.ramdisk_size); - - setup_initrd(params->u1.s.initrd_start, - params->u1.s.initrd_size); - - if (!(params->u1.s.flags & FLAG_READONLY)) - root_mountflags &= ~MS_RDONLY; + struct tag *tag = (struct tag *)params; - from = params->commandline; + /* + * Is the first tag the CORE tag? This differentiates + * between the tag list and the parameter table. + */ + if (tag->hdr.tag == ATAG_CORE) + parse_tags(mdesc->tagtable, mdesc->tagsize, tag); + else + parse_params(params); } if (meminfo.nr_banks == 0) { meminfo.nr_banks = 1; meminfo.bank[0].start = PHYS_OFFSET; - meminfo.bank[0].node = 0; - if (params) - meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; - else - meminfo.bank[0].size = MEM_SIZE; + meminfo.bank[0].size = MEM_SIZE; } init_mm.start_code = (unsigned long) &_text; @@ -385,6 +549,11 @@ paging_init(&meminfo, mdesc); request_standard_resources(&meminfo, mdesc); + /* + * Set up various architecture-specific pointers + */ + init_arch_irq = mdesc->init_irq; + #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -403,8 +572,8 @@ (int)processor_id & 15, elf_platform); p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n", - (loops_per_sec+2500) / 500000, - ((loops_per_sec+2500) / 5000) % 100); + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); p += sprintf(p, "Hardware\t: %s\n", machine_name); diff -u --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 <asm/assembler.h> .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 <aschulz@netwinder.org> * * 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 <linux/module.h> -#include <linux/types.h> - -#include <asm/io.h> - -/* - * 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 <linux/tty.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/init.h> + +#include <asm/elf.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/hardware/dec21285.h> + +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 <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> + +#include <asm/io.h> +#include <asm/page.h> + +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 <linux/init.h> + +#include <asm/mach/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> + +#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 <linux/module.h> +#include <linux/spinlock.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/leds.h> +#include <asm/system.h> +#include <asm/mach-types.h> + +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 <linux/mm.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> + +#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 <linux/sched.h> +#include <linux/init.h> + +#include <asm/io.h> + +#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 <asm/mach/arch.h> -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 <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/mach/irq.h> + +#include <asm/hardware.h> +#include <asm/hardware/dec21285.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/mach-types.h> + +/* + * 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 <linux/config.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/io.h> +#include <asm/hardware/dec21285.h> +#include <asm/mach-types.h> + +#include <asm/mach/map.h> + +/* + * 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 <asm/mach/arch.h> -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 <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/malloc.h> +#include <linux/errno.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/mach/dma.h> + + +#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 <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/errno.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/dma.h> + + +// #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 <nico@cam.org> + * + * 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 <asm/mach/arch.h> -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;i<NR_BANKS;i++) { + if (params->u1.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 <aschulz@netwinder.org> * * 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 <aschulz@netwinder.org> + * + * 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 <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/ioport.h> + +#include <asm/hardware.h> +#include <asm/leds.h> +#include <asm/io.h> +#include <asm/system.h> + +#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 <aschulz@netwinder.org> * * 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 <asm/mach/map.h> #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 <asm/mach/map.h> -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 <linux/types.h> #include <linux/init.h> #include <asm/hardware.h> 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 <linux/mm.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/pgtable.h> -#include <asm/page.h> - -#include <asm/mach/map.h> - -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 <linux/config.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/init.h> - -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/io.h> -#include <asm/hardware/dec21285.h> -#include <asm/mach-types.h> - -#include <asm/mach/map.h> - -/* - * 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 <linux/config.h> -#include <linux/mm.h> +#include <linux/sched.h> #include <linux/init.h> -#include <linux/bootmem.h> #include <asm/hardware.h> #include <asm/pgtable.h> @@ -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 <scottb@netwinder.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> 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 <scottb@netwinder.org> 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 <scottb@netwinder.org> 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 <scottb@netwinder.org> 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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> @@ -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 <scottb@netwinder.org> @@ -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 <asm/pgtable.h> #include <asm/uaccess.h> -/* - * 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 <linux/config.h> #define ASSEMBLER_MACROS_ONLY #include <asm/sv_addr_ag.h> @@ -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 <offset>', 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 <linux/config.h> +#define ASSEMBLER_MACROS_ONLY +#include <asm/sv_addr_ag.h> + + ;; 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 <linux/config.h> +#define ASSEMBLER_MACROS_ONLY +#include <asm/sv_addr_ag.h> + +#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 <asm/sv_addr_ag.h> + + .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 <stdio.h> /* fprintf */ +#include <string.h> +#include <stdlib.h> /* contains exit */ +#include <sys/types.h> /* unistd.h needs this */ +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <unistd.h> /* contains read/write */ +#include <fcntl.h> +#include <linux/a.out.h> +#include <errno.h> + +#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;i<sizeof buf; i++) buf[i]=0; + if ((id=open(argv[1],O_RDONLY,0))<0) + die("Unable to open 'boot'"); + if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) + die("Unable to read header of 'boot'"); + if (((long *) buf)[0]!=intel_long(0x04100301)) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[1]!=intel_long(MINIX_HEADER)) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[3] != 0) + die("Illegal data segment in 'boot'"); + if (((long *) buf)[4] != 0) + die("Illegal bss in 'boot'"); + if (((long *) buf)[5] != 0) + die("Non-Minix header of 'boot'"); + if (((long *) buf)[7] != 0) + die("Illegal symbol table in 'boot'"); + i=read(id,buf,sizeof buf); + fprintf(stderr,"Boot sector %d bytes.\n",i); + if (i != 512) + die("Boot block must be exactly 512 bytes"); + if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55)) + die("Boot block hasn't got boot flag (0xAA55)"); + buf[508] = (char) minor_root; + buf[509] = (char) major_root; + i=write(1,buf,512); + if (i!=512) + die("Write call failed"); + close (id); + + if ((id=open(argv[2],O_RDONLY,0))<0) + die("Unable to open 'setup'"); + if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) + die("Unable to read header of 'setup'"); + if (((long *) buf)[0]!=intel_long(0x04100301)) + die("Non-Minix header of 'setup'"); + if (((long *) buf)[1]!=intel_long(MINIX_HEADER)) + die("Non-Minix header of 'setup'"); + if (((long *) buf)[3] != 0) + die("Illegal data segment in 'setup'"); + if (((long *) buf)[4] != 0) + die("Illegal bss in 'setup'"); + if (((long *) buf)[5] != 0) + die("Non-Minix header of 'setup'"); + if (((long *) buf)[7] != 0) + die("Illegal symbol table in 'setup'"); + for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; 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++) + buf[c] = '\0'; + while (i < setup_sectors * 512) { + c = setup_sectors * 512 - i; + if (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 <asm/mmu.h> #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 <linux/ptrace.h> #include <linux/ioport.h> #include <linux/in.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/string.h> #include <asm/system.h> #include <asm/bitops.h> @@ -53,7 +64,7 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <asm/svinto.h> +#include <asm/svinto.h> /* 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 <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/iobuf.h> + +#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 <linux/config.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/poll.h> +#include <linux/init.h> + +#include <asm/etraxgpio.h> +#include <asm/svinto.h> +#include <asm/io.h> +#include <asm/system.h> + +#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 <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/config.h> + +#include <asm/etraxi2c.h> + +#include <asm/system.h> +#include <asm/svinto.h> +#include <asm/io.h> +#include <asm/delay.h> + +#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 <linux/config.h> #include <linux/version.h> @@ -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 <linux/config.h> #include <linux/circ_buf.h> @@ -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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/major.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/svinto.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/sync_serial.h> + +/* 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 <linux/config.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/version.h> +#include <linux/list.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/svinto.h> + +#include <linux/usb.h> +#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 <linux/types.h> +#include <linux/list.h> + +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 <linux/config.h> #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 <linux/ioport.h> #include <linux/interrupt.h> #include <linux/timex.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/random.h> #include <asm/system.h> @@ -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 <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/interrupt.h> @@ -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 6 10:42:55 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 <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/tty.h> @@ -75,7 +75,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 +180,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 +193,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 +216,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 +244,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 +257,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 <linux/config.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -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 <linux/config.h> + +#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 <linux/vmalloc.h> +#include <asm/io.h> +#include <asm/pgalloc.h> + +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 Tue Apr 17 17:19:24 2001 @@ -9,6 +9,8 @@ define_bool CONFIG_SBUS n define_bool CONFIG_UID16 y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y mainmenu_option next_comment comment 'Code maturity level options' @@ -36,22 +38,25 @@ 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 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 fi @@ -111,6 +116,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 Thu Apr 12 12:46:55 2001 @@ -35,9 +35,11 @@ # CONFIG_MWINCHIPC6 is not set # CONFIG_MWINCHIP2 is not set # CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_CMPXCHG=y +CONFIG_X86_XADD=y CONFIG_X86_BSWAP=y CONFIG_X86_POPAD_OK=y CONFIG_X86_L1_CACHE_SHIFT=5 @@ -383,6 +385,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 +566,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 <Ulrich.Windl@rz.uni-regensburg.de>) - * 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 <rusty@linuxcare.com>). + * (Paul "Rusty" Russell <rusty@rustcorp.com.au>). * Do error notification to user mode if BIOS calls fail. * Move entrypoint offset fix to ...boot/setup.S * where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>). @@ -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 <reese@isn.net>] + * ?: AcerNote-950: oops on reading /proc/apm - workaround is a WIP + * Neale Banks <neale@lowendale.com.au> 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/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 Thu Apr 12 12:22:53 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,12 +72,16 @@ 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_down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_down_read_failed); EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); @@ -97,6 +100,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 <hpa@zytor.com> Use the new centralized CPU feature detects. + + v1.38 + 20010309 Dave Jones <davej@suse.de> + Add support for Cyrix III. + + v1.39 + 20010312 Dave Jones <davej@suse.de> + Ugh, I broke AMD support. + Reworked fix by Troels Walsted Hansen <troels@thule.no> + + v1.40 + 20010327 Dave Jones <davej@suse.de> + Adapted Cyrix III support to include VIA C3. + */ #include <linux/types.h> #include <linux/errno.h> @@ -250,6 +264,7 @@ #include <linux/devfs_fs_kernel.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/pci.h> #define MTRR_NEED_STRINGS #include <asm/mtrr.h> #include <linux/init.h> @@ -269,7 +284,7 @@ #include <asm/hardirq.h> #include <linux/irq.h> -#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 12 12:16:35 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 */ 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 <linux/config.h> #include <linux/sched.h> - #include <asm/semaphore.h> /* @@ -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 6 10:42:55 2001 @@ -58,6 +58,12 @@ * Massive cleanup of CPU detection and bug handling; * Transmeta CPU detection, * H. Peter Anvin <hpa@zytor.com>, November 2000 + * + * Added E820 sanitization routine (removes overlapping memory regions); + * Brian Moyle <bmoyle@mvista.com>, February 2001 + * + * VIA C3 Support. + * Dave Jones <davej@suse.de>, March 2001 */ /* @@ -440,6 +446,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; i<old_nr; i++) + if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) + return -1; + + /* create pointers for initial change-point information (for sorting) */ + for (i=0; i < 2*old_nr; i++) + change_point[i] = &change_point_list[i]; + + /* record all known change-points (starting and ending addresses) */ + chgidx = 0; + for (i=0; i < old_nr; i++) { + change_point[chgidx]->addr = 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 <current_addr> > <last_addr>, swap */ + /* or, if current=<start_addr> & last=<end_addr>, 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; i<overlap_entries; i++) + { + if (overlap_list[i] == change_point[chgidx]->pbios) + 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; i<overlap_entries; i++) + if (overlap_list[i]->type > 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 +676,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 +731,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 +1572,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 +1652,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 +1929,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 +2194,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 +2227,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 Thu Apr 12 12:22:53 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 rwsem.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 <linux/config.h> #include <linux/types.h> #include <linux/string.h> #include <linux/sched.h> @@ -5,6 +6,7 @@ #include <asm/i387.h> #include <asm/hardirq.h> + /* * 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/rwsem.S linux/arch/i386/lib/rwsem.S --- v2.4.3/linux/arch/i386/lib/rwsem.S Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/rwsem.S Thu Apr 12 12:22:53 2001 @@ -0,0 +1,36 @@ +/* rwsem.S: R/W semaphores, register saving wrapper function stubs + * + * Written by David Howells (dhowells@redhat.com). + * Derived from arch/i386/kernel/semaphore.c + */ + +.text +.align 4 +.globl __rwsem_down_read_failed +__rwsem_down_read_failed: + pushl %edx + pushl %ecx + call rwsem_down_read_failed + popl %ecx + popl %edx + ret + +.align 4 +.globl __rwsem_down_write_failed +__rwsem_down_write_failed: + pushl %edx + pushl %ecx + call rwsem_down_write_failed + popl %ecx + popl %edx + ret + +.align 4 +.globl __rwsem_wake +__rwsem_wake: + pushl %edx + pushl %ecx + call rwsem_wake + popl %ecx + popl %edx + ret 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 <linux/string.h> + +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/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 <davidm@hpl.hp.com> +# Copyright (C) 1998-2001 by David Mosberger-Tang <davidm@hpl.hp.com> # 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 <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * * 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 <davidm@hpl.hp.com> + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com> @@ -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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/init.h> @@ -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 <linux/kernel.h> @@ -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 <n0ano@valinux.com> - * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> - * 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 <arun.sharma@intel.com> + * 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 <davidm@hpl.hp.com> * @@ -16,9 +16,10 @@ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/sysctl.h> #include <linux/sched.h> -#include <linux/fs.h> -#include <linux/file.h> +#include <linux/fs.h> +#include <linux/file.h> #include <linux/signal.h> #include <linux/utime.h> #include <linux/resource.h> @@ -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 (call<SYS_SOCKET||call>SYS_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 <drummond@valinux.com> * 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. <Stephan.Zeisset@intel.com> */ @@ -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 <drummond@valinux.com> - * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2001 Hewlett-Packard Co. * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 1999-2001 Stephane Eranian <eranian@hpl.hp.com> * * 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: <goutham.rao@intel.com> - * Skip non-WB memory and ignore empty memory ranges. + * Skip non-WB memory and ignore empty memory ranges. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> @@ -26,6 +25,7 @@ #include <asm/efi.h> #include <asm/io.h> +#include <asm/kregs.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -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 <asm/processor.h> #include <asm/asmmacro.h> - .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 <Matt_Domsch@dell.com> + * + * 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 <Matt_Domsch@dell.com> + * 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 <Matt_Domsch@dell.com> + * v0.01 release to linux-ia64@linuxia64.org + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> /* for capable() */ +#include <linux/mm.h> +#include <linux/module.h> + +#include <asm/efi.h> +#include <asm/uaccess.h> +#ifdef CONFIG_SMP +#include <linux/smp.h> +#endif + +MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); +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; i<variable_name_size / sizeof(efi_char16_t); i++) { + short_name[i] = variable_name[i] & 0xFF; + } + + /* This is ugly, but necessary to separate one vendor's + private variables from another's. */ + + *(short_name + strlen(short_name)) = '-'; + uuid_unparse(vendor_guid, short_name + strlen(short_name)); + + + /* Create the entry in proc */ + new_efivar->entry = 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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com> @@ -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 <nicklin@missioncriticallinux.com> * Patrick O'Rourke <orourke@missioncriticallinux.com> * 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 <linux/config.h> #include <asm/cache.h> #include <asm/errno.h> +#include <asm/kregs.h> #include <asm/offsets.h> #include <asm/processor.h> #include <asm/unistd.h> #include <asm/asmmacro.h> #include <asm/pgtable.h> - -#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 <linux/config.h> + +/* 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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * 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 <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> @@ -14,11 +13,7 @@ #include <asm/unistd.h> #include <asm/page.h> - .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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Intel Corp. @@ -18,16 +19,15 @@ #include <asm/asmmacro.h> #include <asm/fpu.h> -#include <asm/pal.h> +#include <asm/kregs.h> +#include <asm/mmu_context.h> #include <asm/offsets.h> +#include <asm/pal.h> +#include <asm/pgtable.h> #include <asm/processor.h> #include <asm/ptrace.h> #include <asm/system.h> - .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 <asm/hw_irq.h> +#include <linux/irq.h> EXPORT_SYMBOL(isa_irq_to_vector_map); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); #include <linux/in6.h> #include <asm/checksum.h> @@ -40,10 +43,14 @@ EXPORT_SYMBOL(__ia64_memcpy_toio); EXPORT_SYMBOL(__ia64_memset_c_io); -#include <asm/irq.h> -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(disable_irq_nosync); +#include <asm/semaphore.h> +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 <asm/page.h> EXPORT_SYMBOL(clear_page); @@ -57,14 +64,20 @@ EXPORT_SYMBOL(last_cli_ip); #endif +#include <asm/pgalloc.h> + #ifdef CONFIG_SMP +EXPORT_SYMBOL(smp_flush_tlb_all); + #include <asm/current.h> #include <asm/hardirq.h> EXPORT_SYMBOL(synchronize_irq); #include <asm/smp.h> EXPORT_SYMBOL(smp_call_function); +EXPORT_SYMBOL(smp_call_function_single); +EXPORT_SYMBOL(cpu_online_map); #include <linux/smp.h> 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 <asm/uaccess.h> EXPORT_SYMBOL(__copy_user); @@ -111,3 +128,12 @@ extern unsigned long ia64_iobase; EXPORT_SYMBOL(ia64_iobase); + +#include <asm/pal.h> +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 <goutham.rao@intel.com> IRQ vector allocation + * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> 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 <eranian@hpl.hp.com> - * Copyright (C) 1998-2000 David Mosberger <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 David Mosberger <davidm@hpl.hp.com> * * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> 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 <linux/config.h> +#include <asm/asmmacro.h> #include <asm/break.h> +#include <asm/kregs.h> #include <asm/offsets.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -45,6 +47,22 @@ #include <asm/system.h> #include <asm/unistd.h> +#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 <linux/config.h> #include <linux/types.h> @@ -28,7 +28,7 @@ #include <asm/irq.h> - + 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 * <reg_prefix>[<index>] <value> - * - * 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 <linux/config.h> + #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/mca_asm.h> @@ -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 <asm/asmmacro.h> #include <asm/processor.h> - .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 <eranian@hpl.hp.com> - * + * * 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 <linux/config.h> #include <linux/types.h> @@ -36,12 +33,7 @@ MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>"); 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 <venkitac@us.ibm.com> * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2000-2001 Stephane Eranian <eranian@hpl.hp.com> */ #include <linux/config.h> - #include <linux/kernel.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/wrapper.h> +#include <linux/mm.h> +#include <asm/bitops.h> +#include <asm/efi.h> #include <asm/errno.h> #include <asm/hw_irq.h> +#include <asm/page.h> +#include <asm/pal.h> +#include <asm/perfmon.h> +#include <asm/pgtable.h> #include <asm/processor.h> +#include <asm/signal.h> #include <asm/system.h> #include <asm/uaccess.h> -#include <asm/pal.h> - -/* 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 <asm/delay.h> /* 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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */ #include <linux/config.h> @@ -20,6 +20,7 @@ #include <asm/delay.h> #include <asm/efi.h> +#include <asm/perfmon.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/sal.h> @@ -27,8 +28,6 @@ #include <asm/unwind.h> #include <asm/user.h> -#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 <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * 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 <asm/rse.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/unwind.h> /* * 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 <asm/unwind.h> - 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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com> * Copyright (C) 1999 VA Linux Systems @@ -42,16 +42,20 @@ # include <linux/blk.h> #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 <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * 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 <drummond@valinux.com> - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * + * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * * Lots of stuff stolen from arch/alpha/kernel/smp.c * * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy calibration on each CPU. @@ -37,8 +37,8 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/page.h> -#include <asm/pgtable.h> #include <asm/pgalloc.h> +#include <asm/pgtable.h> #include <asm/processor.h> #include <asm/ptrace.h> #include <asm/sal.h> @@ -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 <NUM>. */ -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 <func> * 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 <linux/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/smp.h> -#include <linux/kernel_stat.h> -#include <linux/mm.h> -#include <linux/delay.h> - -#include <asm/atomic.h> -#include <asm/bitops.h> -#include <asm/current.h> -#include <asm/delay.h> -#include <asm/efi.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/sal.h> -#include <asm/system.h> -#include <asm/unistd.h> - -/* - * 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 <eranian@hpl.hp.com> - * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 David Mosberger <davidm@hpl.hp.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> * Copyright (C) 1999-2000 VA Linux Systems * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com> @@ -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<<IA64_USEC_PER_CYC_SHIFT) + + itc_freq/2)/itc_freq; /* Setup the CPU local timer tick */ ia64_cpu_local_tick(); @@ -299,11 +283,7 @@ void __init time_init (void) { - /* we can't do request_irq() here because the kmalloc() would fail... */ - irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU; - irq_desc[TIMER_IRQ].handler = &irq_type_ia64_sapic; - setup_irq(TIMER_IRQ, &timer_irqaction); - + register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction); efi_gettimeofday(&xtime); ia64_init_itm(); } diff -u --recursive --new-file v2.4.3/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.4.3/linux/arch/ia64/kernel/traps.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/traps.c Thu Apr 5 12:51:47 2001 @@ -7,8 +7,6 @@ * 05/12/00 grao <goutham.rao@intel.com> : 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 <eranian@hpl.hp.com> + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * + * 2001/01/17 Add support emulation of unaligned kernel accesses. */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/smp_lock.h> + #include <asm/uaccess.h> #include <asm/rse.h> #include <asm/processor.h> @@ -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 <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ /* * 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 <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> #include <asm/unwind.h> -#ifdef CONFIG_IA64_NEW_UNWIND - #include <asm/delay.h> #include <asm/page.h> #include <asm/ptrace.h> @@ -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 <eranian@hpl.hp.com> - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> #include <asm/page.h> - .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 <eranian@hpl.hp.com> */ @@ -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 <eranian@hpl.hp.com> */ #include <asm/asmmacro.h> @@ -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 <eranian@hpl.hp.com> * * 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 <asm/asmmacro.h> -// 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 <eranian@hpl.hp.com> * @@ -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 <eranian@hpl.hp.com> * */ @@ -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 <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> #include <asm/page.h> - .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 <eranian@hpl.hp.com> */ @@ -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 <eranian@hpl.hp.com> * * 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 <davidm@hpl.hp.com> + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * * 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 <davidm@hpl.hp.com> + * + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * 00/03/06 D. Mosberger Fixed to return proper return value (bug found by * by Andreas Schwab <schwab@suse.de>). @@ -18,18 +18,6 @@ #include <asm/asmmacro.h> -#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 <davidm@hpl.hp.com> + * + * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> -/* 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 <linux/mm.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -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 <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> @@ -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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> #include <linux/kernel.h> @@ -23,116 +23,33 @@ #include <asm/pgalloc.h> #include <asm/sal.h> #include <asm/system.h> +#include <asm/uaccess.h> /* 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 <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * - * 08/02/00 A. Mallick <asit.k.mallick@intel.com> - * Modified RID allocation for SMP + * 08/02/00 A. Mallick <asit.k.mallick@intel.com> + * Modified RID allocation for SMP * Goutham Rao <goutham.rao@intel.com> * 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 <asm/pgtable.h> */ @@ -49,7 +49,7 @@ #include <linux/irq.h> -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 <asm/efi.h> #include <asm/pal.h> #include <asm/sal.h> @@ -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<DEVICE_DRIVER_HASH_SIZE; i++) { - spinlock_init(&device_driver_lock[i], "devdrv"); + spin_lock_init(&device_driver_lock[i]); device_driver_hash[i] = NULL; } @@ -877,7 +875,7 @@ static int driver_prefix_hash(char *prefix) { -#ifdef notyet +#ifdef LATER int accum = 0; char nextchar; @@ -903,10 +901,10 @@ device_driver_t device_driver_alloc(char *prefix) { -#ifdef notyet +#ifdef LATER int which_hash; device_driver_t new_driver; - int s; + unsigned long s; which_hash = driver_prefix_hash(prefix); @@ -964,9 +962,9 @@ void device_driver_free(device_driver_t driver) { -#ifdef notyet +#ifdef LATER int which_hash; - int s; + unsigned long s; if (!driver) return; @@ -1027,10 +1025,10 @@ device_driver_t device_driver_get(char *prefix) { -#ifdef notyet +#ifdef LATER int which_hash; device_driver_t drvscan; - int s; + unsigned long s; if (prefix == NULL) return(NULL); @@ -1060,7 +1058,7 @@ device_driver_t device_driver_getbydev(devfs_handle_t device) { -#ifdef notyet +#ifdef LATER struct bdevsw *my_bdevsw; struct cdevsw *my_cdevsw; @@ -1093,7 +1091,7 @@ struct bdevsw *my_bdevsw, struct cdevsw *my_cdevsw) { -#ifdef notyet +#ifdef LATER int i; if (!driver) @@ -1194,7 +1192,7 @@ void device_info_set(devfs_handle_t device, void *info) { -#ifdef notyet +#ifdef LATER hwgraph_fastinfo_set(device, (arbitrary_info_t)info); #endif FIXME("device_info_set"); @@ -1207,7 +1205,7 @@ void * device_info_get(devfs_handle_t device) { -#ifdef notyet +#ifdef LATER return((void *)hwgraph_fastinfo_get(device)); #else FIXME("device_info_get"); @@ -1222,7 +1220,7 @@ int device_driver_sysgen_thread_pri_get(char *dev_prefix) { -#ifdef notyet +#ifdef LATER int pri; char *pri_s; char *class; diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/eeprom.c linux/arch/ia64/sn/io/eeprom.c --- v2.4.3/linux/arch/ia64/sn/io/eeprom.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/eeprom.c Thu Apr 5 12:51:47 2001 @@ -53,7 +53,6 @@ #include <asm/sn/labelcl.h> #include <asm/sn/eeprom.h> #include <asm/sn/ksys/i2c.h> -#include <asm/sn/cmn_err.h> /* #include <sys/SN/SN1/ip27log.h> */ #include <asm/sn/router.h> #include <asm/sn/module.h> @@ -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 <linux/types.h> +#include <linux/slab.h> +#include <asm/smp.h> +#include <asm/sn/sgi.h> +#include <asm/sn/iograph.h> +#include <asm/sn/invent.h> +#include <asm/sn/hcl.h> +#include <asm/sn/labelcl.h> +#include <asm/sn/nodemask.h> +#include <asm/sn/sn_private.h> +#include <asm/sn/klconfig.h> +#include <asm/sn/synergy.h> +#include <asm/sn/sn_cpuid.h> +#include <asm/sn/pci/pciio.h> +#include <asm/sn/pci/pcibr.h> +#include <asm/sn/xtalk/xtalk.h> +#include <asm/sn/pci/pcibr_private.h> +#include <asm/sn/intr.h> + +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; sn<NUM_SUBNODES; sn++) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_PEND, -1); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_A_CLR, -1); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS0_B_CLR, -1); + REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_0, 0); + REMOTE_HUB_PI_S(nasid, sn, PI_SPURIOUS_HDR_1, 0); + } + + REMOTE_HUB_L(nasid, MD_DIR_ERROR_CLR); + REMOTE_HUB_L(nasid, MD_MEM_ERROR_CLR); + REMOTE_HUB_L(nasid, MD_MISC1_ERROR_CLR); + REMOTE_HUB_L(nasid, MD_PROTOCOL_ERR_CLR); + + /* + * Make sure spurious write response errors are cleared + * (values are from hub_set_prb()) + */ + for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) { + iprb_t prb; + + prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t))); + + /* Clear out some fields */ + prb.iprb_ovflow = 1; + prb.iprb_bnakctr = 0; + prb.iprb_anakctr = 0; + + /* + * PIO reads in fire-and-forget mode on bedrock 1.0 don't + * frob the credit count properly, making the responses appear + * spurious. So don't use fire-and-forget mode. Bug 761802. + */ + prb.iprb_ff = 0; /* disable fire-and-forget mode by default */ + + prb.iprb_xtalkctr = 3; /* approx. PIO credits for the widget */ + + REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); + } + + REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1); + idsr = REMOTE_HUB_L(nasid, IIO_IIDSR); + REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK))); + + REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); + /* No need to clear NI_PORT_HEADER regs; they are continually overwritten*/ + + REMOTE_HUB_S(nasid, LB_ERROR_MASK_CLR, -1); + REMOTE_HUB_S(nasid, LB_ERROR_HDR1, 0); + + /* Clear XB error regs, in order */ + for (i = 0; + i <= XB_FIRST_ERROR_CLEAR - XB_POQ0_ERROR_CLEAR; + i += sizeof(hubreg_t)) { + REMOTE_HUB_S(nasid, XB_POQ0_ERROR_CLEAR + i, 0); + } +} + + +/* + * Function : hub_error_init + * Purpose : initialize the error handling requirements for a given hub. + * Parameters : cnode, the compact nodeid. + * Assumptions : Called only once per hub, either by a local cpu. Or by a + * remote cpu, when this hub is headless.(cpuless) + * Returns : None + */ + +void +hub_error_init(cnodeid_t cnode) +{ + nasid_t nasid; + + nasid = cnodeid_to_nasid(cnode); + hub_error_clear(nasid); + +#ifdef ajm + if (cnode == 0) { + /* + * Allocate log for storing the node specific error info + */ + for (i = 0; i < numnodes; i++) { + kl_error_log[i] = kmem_zalloc_node(sizeof(sn0_error_log_t), + KM_NOSLEEP, i); + hub_err_count[i] = kmem_zalloc_node(sizeof(hub_errcnt_t), + VM_DIRECT | KM_NOSLEEP, i); + ASSERT_ALWAYS(kl_error_log[i] && hub_err_count[i]); + } + } + + /* + * Assumption: There will be only one cpu who will initialize + * a hub. we need to setup the ii and each pi error interrupts. + * The SN1 hub (bedrock) has two PI, one for up to two processors. + */ + + if (cpuid_to_cnodeid(smp_processor_id()) == cnode) { + int generic_intr_mask = PI_ERR_GENERIC; /* These interrupts are sent to only 1 CPU per NODE */ + + ASSERT_ALWAYS(kl_error_log[cnode]); + ASSERT_ALWAYS(hub_err_count[cnode]); + MD_ERR_LOG_INIT(kl_error_log[cnode]); + + /* One for each CPU */ + recover_error_init(RECOVER_ERROR_TABLE(cnode, 0)); + recover_error_init(RECOVER_ERROR_TABLE(cnode, 1)); + recover_error_init(RECOVER_ERROR_TABLE(cnode, 2)); + recover_error_init(RECOVER_ERROR_TABLE(cnode, 3)); + + /* + * Setup error intr masks. + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + int cpuA_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_A); + int cpuB_present = REMOTE_HUB_PI_L(nasid, sn, PI_CPU_ENABLE_B); + + if (cpuA_present) { + if (cpuB_present) { /* A && B */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, + (PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_A|generic_intr_mask)); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, + (PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_B)); + + } else { /* A && !B */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, + (PI_FATAL_ERR_CPU_A | PI_MISC_ERR_CPU_A|generic_intr_mask)); + } + generic_intr_mask = 0; + } else { + if (cpuB_present) { /* !A && B */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, + (PI_FATAL_ERR_CPU_B | PI_MISC_ERR_CPU_B|generic_intr_mask)); + generic_intr_mask = 0; + + } else { /* !A && !B */ + /* nothing to set up */ + } + } + } + + /* + * Turn off UNCAC_UNCORR interrupt in the masks. Anyone interested + * in these errors will peek at the int pend register to see if its + * set. + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_A); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, (misc & ~PI_ERR_UNCAC_UNCORR_A)); + misc = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_INT_MASK_B); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, (misc & ~PI_ERR_UNCAC_UNCORR_B)); + } + + /* + * enable all error indicators to turn on, in case of errors. + * + * This is not good on single cpu node boards. + **** LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); + */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_A_CLR, 0); + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STATUS1_B_CLR, 0); + } + + /* Set up stack for each present processor */ + for(sn=0; sn<NUM_SUBNODES; sn++) { + if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_A)) { + SN0_ERROR_LOG(cnode)->el_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; sn<NUM_SUBNODES; sn++) { + if (REMOTE_HUB_PI_L(nasid, sn, PI_CPU_PRESENT_B)) { + __psunsigned_t addr_a = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_A); + __psunsigned_t addr_b = REMOTE_HUB_PI_L(nasid, sn, PI_ERR_STACK_ADDR_B); + if ((addr_a & ~0xff) == (addr_b & ~0xff)) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_STACK_ADDR_B, + addr_b + PI_SPOOL_SIZE_BYTES); + + 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); + + } + } + } +#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; sn<NUM_SUBNODES; sn++) { + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_A, 0); /* not necessary */ + REMOTE_HUB_PI_S(nasid, sn, PI_ERR_INT_MASK_B, 0); /* not necessary */ + } + } +#endif /* ajm */ + /* + * Now setup the hub ii and ni error interrupt handler. + */ + + hubii_eint_init(cnode); + hubni_eint_init(cnode); + +#ifdef ajm + /*** XXX FIXME XXX resolve the following***/ + /* INT_PEND1 bits set up for one hub only: + * SHUTDOWN_INTR + * MD_COR_ERR_INTR + * COR_ERR_INTR_A and COR_ERR_INTR_B should be sent to the + * appropriate CPU only. + */ + + if (cnode == 0) { + error_consistency_check.eps_state = 0; + error_consistency_check.eps_cpuid = -1; + spinlock_init(&error_consistency_check.eps_lock, "error_dump_lock"); + } +#endif + + nodepda->huberror_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 <linux/slab.h> #include <asm/sn/types.h> #include <asm/sn/sgi.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/iobus.h> #include <asm/sn/iograph.h> #include <asm/param.h> @@ -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 <asm/sn/hcl.h> #include <asm/sn/labelcl.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/agent.h> -#ifdef CONFIG_IA64_SGI_IO #include <asm/sn/kldir.h> -#endif #include <asm/sn/gda.h> #include <asm/sn/klconfig.h> #include <asm/sn/router.h> #include <asm/sn/xtalk/xbow.h> #include <asm/sn/hcl_util.h> -#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 <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <asm/sn/sgi.h> @@ -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 <linux/types.h> #include <linux/config.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <asm/sn/sgi.h> #include <asm/sn/iograph.h> #include <asm/sn/invent.h> @@ -42,7 +43,6 @@ #include <asm/sn/labelcl.h> #include <asm/sn/eeprom.h> #include <asm/sn/ksys/i2c.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/router.h> #include <asm/sn/module.h> #include <asm/sn/ksys/l1.h> @@ -51,6 +51,20 @@ #include <asm/sn/sn1/uart16550.h> +/* + * 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 <asm/sn/labelcl.h> #include <asm/sn/eeprom.h> #include <asm/sn/ksys/i2c.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/router.h> #include <asm/sn/module.h> #include <asm/sn/ksys/l1.h> @@ -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 <linux/types.h> -#include <linux/config.h> #include <asm/sn/sgi.h> #include <asm/sn/invent.h> #include <asm/sn/hcl.h> @@ -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 <BOMB! define new cputype here > -#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; sn<NUM_SUBNODES; sn++) { SNPDA(npda,sn)->prof_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 <asm/sn/pci/pcibr.h> #include <asm/sn/xtalk/xtalk.h> #include <asm/sn/pci/pcibr_private.h> +#include <asm/sn/intr.h> + #if DEBUG_INTR_TSTAMP_DEBUG #include <sys/debug.h> @@ -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; i<NUM_SUBNODES; i++) subnode_done[i] = 0; - for (; cpu<maxcpus && cpu_enabled(cpu) && cputocnode(cpu) == cnode; cpu++) { + for (; cpu<smp_num_cpus && cpu_enabled(cpu) && cpuid_to_cnodeid(cpu) == cnode; cpu++) { int which_subnode = cpuid_to_subnode(cpu); if (subnode_done[which_subnode]) continue; @@ -1594,7 +1594,6 @@ } } -#endif /* BRINGUP */ /* * Check and clear interrupts. @@ -1612,7 +1611,7 @@ for (i = 0; i < N_INTPEND_BITS; i++) { if (bits & (1 << i)) { #ifdef INTRDEBUG - printk( "Nasid %d interrupt bit %d set in %s", + PRINT_WARNING("Nasid %d interrupt bit %d set in %s", nasid, i, name); #endif LOCAL_HUB_CLR_INTR(base_level + i); diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/io/ml_iograph.c linux/arch/ia64/sn/io/ml_iograph.c --- v2.4.3/linux/arch/ia64/sn/io/ml_iograph.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/ml_iograph.c Thu Apr 12 12:16:35 2001 @@ -32,6 +32,13 @@ extern int maxnodes; +/* #define IOGRAPH_DEBUG */ +#ifdef IOGRAPH_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* IOGRAPH_DEBUG */ + /* #define PROBE_TEST */ /* At most 2 hubs can be connected to an xswitch */ @@ -44,7 +51,7 @@ * xswitch vertex is created. */ typedef struct xswitch_vol_s { - struct semaphore xswitch_volunteer_mutex; + mutex_t xswitch_volunteer_mutex; int xswitch_volunteer_count; devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; } *xswitch_vol_t; @@ -56,7 +63,7 @@ int rc; xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - init_MUTEX(&xvolinfo->xswitch_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; i<num_volunteer; i++) { - hubv = xvolinfo->xswitch_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 <sys/sn/iograph.h> -#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 <sys/asm/sn/ioerror_handling.h> -#else #include <asm/sn/ioerror_handling.h> -#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<NUM_BASE_IO_SCSI_CTLR; i++) { if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) { - printk("%d ", i); + DBG("%d ", i); viable_found=1; } } if (viable_found) - printk("\n"); + DBG("\n"); else - printk("none found!\n"); + DBG("none found!\n"); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER if (kdebug) debug("ring"); #endif @@ -1579,4 +1523,132 @@ *tmp2++ = '/'; strcpy(tmp2, EDGE_LBL_BLOCK); strcpy(devnm,tmpnm); +} + +static +struct io_brick_map_s io_brick_tab[] = { + +/* Ibrick widget number to PCI bus number map */ + { + 'I', /* Ibrick type */ + /* PCI Bus # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 0, /* 0x8 */ + 0, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 0, /* 0xc */ + 0, /* 0xd */ + 2, /* 0xe */ + 1 /* 0xf */ + } + }, + +/* Pbrick widget number to PCI bus number map */ + { + 'P', /* Pbrick type */ + /* PCI Bus # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 2, /* 0x8 */ + 1, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 5, /* 0xc */ + 6, /* 0xd */ + 4, /* 0xe */ + 3 /* 0xf */ + } + }, + +/* Xbrick widget to XIO slot map */ + { + 'X', /* Xbrick type */ + /* XIO Slot # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 1, /* 0x8 */ + 2, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 3, /* 0xc */ + 4, /* 0xd */ + 0, /* 0xe */ + 0 /* 0xf */ + } + } +}; + +/* + * Use the brick's type to map a widget number to a meaningful int + */ +int +io_brick_map_widget(char brick_type, int widget_num) +{ + int num_bricks, i; + + /* Calculate number of bricks in table */ + num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]); + + /* Look for brick prefix in table */ + for (i = 0; i < num_bricks; i++) { + if (brick_type == io_brick_tab[i].ibm_type) + return(io_brick_tab[i].ibm_map_wid[widget_num]); + } + + return 0; + +} + +/* + * Use the device's vertex to map the device's widget to a meaningful int + */ +int +io_path_map_widget(devfs_handle_t vertex) +{ + char hw_path_name[MAXDEVNAME]; + char *wp, *bp, *sp = NULL; + int widget_num; + long atoi(char *); + int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); + + + /* Get the full path name of the vertex */ + if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name, + MAXDEVNAME)) + return 0; + + /* Find the widget number in the path name */ + wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/"); + if (wp == NULL) + return 0; + widget_num = atoi(wp+7); + if (widget_num < XBOW_PORT_8 || widget_num > 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 <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <asm/sn/sgi.h> #include <asm/sn/invent.h> #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/xtalk/xbow.h> #include <asm/sn/pci/bridge.h> #include <asm/sn/klconfig.h> @@ -24,12 +22,17 @@ #include <asm/sn/pci/pcibr.h> #include <asm/sn/xtalk/xswitch.h> #include <asm/sn/nodepda.h> +#include <asm/sn/sn_cpuid.h> -#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 <linux/pci.h> #include <asm/sn/types.h> #include <asm/sn/sgi.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/iobus.h> #include <asm/sn/iograph.h> #include <asm/param.h> @@ -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 <asm/sn/types.h> #include <asm/sn/hack.h> #include <asm/sn/sgi.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/iobus.h> #include <asm/sn/iograph.h> #include <asm/param.h> @@ -32,23 +31,32 @@ #include <asm/sn/xtalk/xtalkaddrs.h> #include <asm/sn/klconfig.h> #include <asm/sn/io.h> -#include <asm/sn/pci/pci_bus_cvlink.h> #include <asm/sn/pci/pciio.h> // #include <sys/ql.h> #include <asm/sn/pci/pcibr.h> #include <asm/sn/pci/pcibr_private.h> extern int bridge_rev_b_data_check_disable; +#include <asm/sn/pci/pci_bus_cvlink.h> #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/<module_number> */ - 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 <asm/io.h> #include <asm/sn/sgi.h> @@ -32,9 +29,9 @@ #include <asm/sn/pci/pcibr.h> #include <asm/sn/pci/pcibr_private.h> #include <asm/sn/iobus.h> -#include <asm/sn/pci/pci_bus_cvlink.h> #include <asm/sn/types.h> #include <asm/sn/alenlist.h> +#include <asm/sn/pci/pci_bus_cvlink.h> /* * 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 <linux/types.h> +#include <linux/config.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <asm/sn/sgi.h> +#include <asm/sn/addrs.h> +#include <asm/sn/arch.h> +#include <asm/sn/iograph.h> +#include <asm/sn/invent.h> +#include <asm/sn/hcl.h> +#include <asm/sn/labelcl.h> +#include <asm/sn/xtalk/xwidget.h> +#include <asm/sn/pci/bridge.h> +#include <asm/sn/pci/pciio.h> +#include <asm/sn/pci/pcibr.h> +#include <asm/sn/pci/pcibr_private.h> +#include <asm/sn/pci/pci_defs.h> +#include <asm/sn/prio.h> +#include <asm/sn/ioerror_handling.h> +#include <asm/sn/xtalk/xbow.h> +#include <asm/sn/ioc3.h> +#include <asm/sn/eeprom.h> +#include <asm/sn/sn1/bedrock.h> +#include <asm/sn/sn_private.h> +#if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) +#include <asm/sn/sn1/hubio.h> +#include <asm/sn/sn1/hubio_next.h> +#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 <asm/sn/pci/pciba.h> + +/* 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 <linux/types.h> #include <linux/config.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/sn/sgi.h> #include <asm/sn/addrs.h> #include <asm/sn/arch.h> @@ -22,7 +23,6 @@ #include <asm/sn/invent.h> #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> -#include <asm/sn/cmn_err.h> #include <asm/sn/xtalk/xwidget.h> #include <asm/sn/pci/bridge.h> #include <asm/sn/pci/pciio.h> @@ -41,6 +41,14 @@ #include <asm/sn/sn1/hubio_next.h> #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 <asm/sn/io.h> +#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 <sys/idbg.h> #include <sys/idbgentry.h> @@ -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 <linux/config.h> #include <linux/slab.h> #include <asm/sn/sgi.h> +#include <asm/sn/xtalk/xbow.h> /* Must be before iograph.h to get MAX_PORT_NUM */ #include <asm/sn/iograph.h> #include <asm/sn/invent.h> #include <asm/sn/hcl.h> @@ -23,6 +24,7 @@ #include <asm/sn/ioerror_handling.h> #include <asm/sn/pci/pciio.h> #include <asm/sn/pci/pciio_private.h> +#include <asm/sn/sn_sal.h> #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 <asm/sn/pci/pciio.h> #include <asm/sn/slotnum.h> -#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 <asm/sn/sn_private.h> #include <asm/sn/synergy.h> -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 <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <linux/sched.h> #include <asm/sn/sgi.h> @@ -17,19 +16,18 @@ #include <asm/sn/invent.h> #include <asm/sn/hcl.h> #include <asm/sn/labelcl.h> +#include <asm/sn/hack.h> #include <asm/sn/pci/bridge.h> #include <asm/sn/xtalk/xtalk_private.h> -#define DEBUG 1 -#define XBOW_DEBUG 1 +/* #define DEBUG 1 */ +/* #define XBOW_DEBUG 1 */ /* * Files needed to get the device driver entry points */ -/* #include <asm/cred.h> */ - #include <asm/sn/xtalk/xbow.h> #include <asm/sn/xtalk/xtalk.h> #include <asm/sn/xtalk/xswitch.h> @@ -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 <linux/types.h> -#include <linux/config.h> #include <linux/slab.h> #include <asm/sn/sgi.h> #include <asm/sn/iobus.h> @@ -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<<PAGE_SHIFT, 0); - free_unused_memmap_node(i); - } - dump_node_data(); -} - - void dump_node_data(void) { diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/error.c linux/arch/ia64/sn/sn1/error.c --- v2.4.3/linux/arch/ia64/sn/sn1/error.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/error.c Thu Apr 5 12:51:47 2001 @@ -0,0 +1,149 @@ + + +/* + * SN1 Platform specific error Support + * + * Copyright (C) 2001 Silicon Graphics, Inc. + * Copyright (C) 2001 Alan Mayer (ajm@sgi.com) + */ + + + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/ptrace.h> +#include <linux/devfs_fs_kernel.h> +#include <asm/smp.h> +#include <asm/sn/sn_cpuid.h> +#include <asm/sn/sn1/bedrock.h> +#include <asm/sn/intr.h> +#include <asm/sn/addrs.h> + +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<<GFX_INTR_A)) == + (intpend_val & ~(1L<<GFX_INTR_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<GFX_INTR_B)) == + (intpend_val & ~(1L<<GFX_INTR_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<PG_MIG_INTR)) == + (intpend_val & ~(1L<<PG_MIG_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<UART_INTR)) == + (intpend_val & ~(1L<<UART_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<CC_PEND_A)) == + (intpend_val & ~(1L<<CC_PEND_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + if ( (bit = ~(1L<<CC_PEND_B)) == + (intpend_val & ~(1L<<CC_PEND_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + return; + } + printk("Received SGI_UART_IRQ (65), but no intpend0 bits were set???\n"); + return; + case SGI_HUB_ERROR_IRQ: + // These are mostly error interrupts of various + // sorts. We need to do more than panic here, but + // what the heck, this is bring up. + intpend_val = LOCAL_HUB_L(PI_INT_PEND1); + + if ( (bit = ~(1L<<XB_ERROR)) == + (intpend_val & ~(1L<<XB_ERROR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED XB_ERROR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<LB_ERROR)) == + (intpend_val & ~(1L<<LB_ERROR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED LB_ERROR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<NACK_INT_A)) == + (intpend_val & ~(1L<<NACK_INT_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED NACK_INT_A on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<NACK_INT_B)) == + (intpend_val & ~(1L<<NACK_INT_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED NACK_INT_B on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<CLK_ERR_INTR)) == + (intpend_val & ~(1L<<CLK_ERR_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED CLK_ERR_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<COR_ERR_INTR_A)) == + (intpend_val & ~(1L<<COR_ERR_INTR_A)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED COR_ERR_INTR_A on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<COR_ERR_INTR_B)) == + (intpend_val & ~(1L<<COR_ERR_INTR_B)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED COR_ERR_INTR_B on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<MD_COR_ERR_INTR)) == + (intpend_val & ~(1L<<MD_COR_ERR_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED MD_COR_ERR_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<NI_ERROR_INTR)) == + (intpend_val & ~(1L<<NI_ERROR_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED NI_ERROR_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + if ( (bit = ~(1L<<MSC_PANIC_INTR)) == + (intpend_val & ~(1L<<MSC_PANIC_INTR)) ) { + LOCAL_HUB_CLR_INTR(bit); + panic("RECEIVED MSC_PANIC_INTR on cpu %d, cnode %d\n", + smp_processor_id(), + cpuid_to_cnodeid(smp_processor_id())); + } + printk("Received SGI_XB_ERROR_IRQ (182) but no intpend1 bits are set???\n"); + return; + default: + printk("Received invalid irq in snia_error_intr_handler()/n"); + } +} diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/iomv.c linux/arch/ia64/sn/sn1/iomv.c --- v2.4.3/linux/arch/ia64/sn/sn1/iomv.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/sn1/iomv.c Thu Apr 5 12:51:47 2001 @@ -25,11 +25,8 @@ * for accessing registers in bedrock local block * (so we don't do port&0xfff) */ - if (port == 0x1f6 || port == 0x1f7 - || port == 0x3f6 || port == 0x3f7 - || port == 0x1f0 || port == 0x1f1 - || port == 0x1f3 || port == 0x1f4 - || port == 0x1f2 || port == 0x1f5) { + if (port >= 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 <linux/config.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/slab.h> #include <asm/current.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -30,28 +32,23 @@ #include <asm/sn/sn1/arch.h> #include <asm/sn/synergy.h> +#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; j<IA64_MAX_VECTORED_IRQ+1; j++) { - spin_lock_init(&sn1_node_actions[i][j].action_list_lock); + if (idesc_from_vector(i)->handler == &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=<n>\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; i<k_linecount; i++) { + printk(" %lx", blocks[i]); + if (i%4 == 3) + printk("\n"); + } + printk("\n"); +} + + +static void set_thread_state(int cpuid, int state) { if (k_threadprivate[cpuid]->threadstate == 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 <asm/machvec_init.h> +#include <asm/io.h> +#include <linux/pci.h> +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 <linux/config.h> @@ -11,32 +11,23 @@ #include <asm/efi.h> #include <asm/sn/mmzone_sn1.h> -# 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_BANK_ADDR_SHIFT)); + start + (i<<SN1_BANK_ADDR_SHIFT)); } while (i<SN1_MAX_BANK_PER_NODE); } @@ -98,7 +91,6 @@ cnodeid = NASID_TO_CNODEID(nasid); bankid = GetBankId(__pa(vaddr)); nodemem[cnodeid].start = MIN(nodemem[cnodeid].start, vaddr); - nodemem[cnodeid].usable = MIN(nodemem[cnodeid].usable, vaddr); nvaddr = (unsigned long)__va((unsigned long)(++nasid) << SN1_NODE_ADDR_SHIFT); nodemem[cnodeid].end = MAX(nodemem[cnodeid].end, MIN(end, nvaddr)); @@ -118,11 +110,14 @@ pgtbl_size_ok(int nid) { unsigned long numpfn, bank0size, nodesize ; + unsigned long start = nodemem[nid].start; + + start = ((start >> 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<MAXNODES;i++) { - nodemem[i].usable = nodemem[i].start = -1 ; - nodemem[i].end = 0 ; - memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole)) ; + for (i = 0; i < MAXNODES; i++) { + nodemem[i].start = nodemem[i].bstart = -1; + nodemem[i].end = nodemem[i].bsize = nodemem[i].mtot = 0; + nodemem[i].done = DONE_NOTHING; + memset(&nodemem[i].hole, -1, sizeof(nodemem[i].hole)); } - efi_memmap_walk(build_nodemem_map, 0) ; + efi_memmap_walk(build_nodemem_map, 0); - /* - * Run thru all the nodes, adjusting their starts. This is needed - * because efi_memmap_walk() might not process certain mds that - * are marked reserved for PROM at node low memory. - */ - for (i = 0; i < maxnodes; i++) - nodemem[i].start = ((nodemem[i].start >> 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<maxnodes;i++) - check_pgtbl_size(i) ; - - for (i=0;i<maxnodes;i++) - setup_node_bootmem(nodemem[i].start, nodemem[i].end, nodemem[i].usable); + for (i = 0; i < maxnodes; i++) + check_pgtbl_size(i); - /* - * Mark the holes as reserved, so the corresponding mem_map - * entries will not be marked allocatable in free_all_bootmem*(). - */ - for (i = 0; i < maxnodes; i++) { - int j = 0 ; - u64 holestart = -1 ; - - do { - holestart = nodemem[i].hole[j++]; - while ((j < SN1_MAX_BANK_PER_NODE) && - (nodemem[i].hole[j] == (u64)-1)) - j++; - if (j < SN1_MAX_BANK_PER_NODE) - reserve_bootmem_node(NODE_DATA(i), - __pa(holestart), (nodemem[i].start + - ((long)j << SN1_BANK_ADDR_SHIFT) - - holestart)); - } while (j < SN1_MAX_BANK_PER_NODE); - } + dump_nodemem_map(maxnodes); - dump_nodemem_map(maxnodes) ; + efi_memmap_walk(find_node_bootmem, 0); + efi_memmap_walk(build_node_bootmem, 0); } #endif +void __init +discontig_paging_init(void) +{ + int i; + unsigned long max_dma, zones_size[MAX_NR_ZONES], holes_size[MAX_NR_ZONES]; + extern void dump_node_data(void); + + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> 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<<PAGE_SHIFT, holes_size); + free_unused_memmap_node(i); + } + dump_node_data(); +} + /* * This used to be invoked from an SN1 specific hack in efi_memmap_walk. * It tries to ignore banks which the kernel is ignoring because bank 0 @@ -386,10 +381,10 @@ int i,j; printk("NODEMEM_S info ....\n") ; - printk("Node start end usable\n"); + printk("Node start end\n"); for (i=0;i<maxnodes;i++) { - printk("%d 0x%lx 0x%lx 0x%lx\n", - i, nodemem[i].start, nodemem[i].end, nodemem[i].usable); + printk("%d 0x%lx 0x%lx\n", + i, nodemem[i].start, nodemem[i].end); printk("Holes -> ") ; for (j=0;j<SN1_MAX_BANK_PER_NODE;j++) printk("0x%lx ", nodemem[i].hole[j]) ; diff -u --recursive --new-file v2.4.3/linux/arch/ia64/sn/sn1/probe.c linux/arch/ia64/sn/sn1/probe.c --- v2.4.3/linux/arch/ia64/sn/sn1/probe.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/probe.c Thu Apr 5 12:51:47 2001 @@ -0,0 +1,62 @@ +/* + * Platform dependent support for IO probing. + * + * Copyright (C) 2000 Silicon Graphics + * Copyright (C) 2000 Jack Steiner (steiner@sgi.com) + */ + +#include <asm/sn/sn_sal.h> + +/* + * 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 <linux/sched.h> #include <linux/ioport.h> #include <linux/mm.h> +#include <linux/serial.h> #include <asm/sn/mmzone_sn1.h> #include <asm/io.h> +#include <asm/dma.h> #include <asm/machvec.h> #include <asm/system.h> #include <asm/processor.h> +#include <asm-ia64/sn/arch.h> +#include <asm-ia64/sn/addrs.h> + + +/* + * 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 <linux/config.h> +#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 <linux/module.h> + +#include <asm/machvec.h> + +/* + * 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 <linux/mm.h> +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 <lord@sgi.com> + * + * Paul Cassella <pwc@sgi.com> + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/semaphore.h> +#include <asm/hardirq.h> +#include <asm/softirq.h> +#include <asm/current.h> + +#include <asm/sn/sv.h> + +/* 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 <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/spinlock.h> +#include <linux/proc_fs.h> #include <asm/ptrace.h> #include <linux/devfs_fs_kernel.h> @@ -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 <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * * 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 <linux/blk.h> #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 <linux/tty.h> +#include <linux/major.h> +#include <linux/ptrace.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/fs.h> + +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 <linux/init.h> #include <linux/kernel.h> @@ -12,9 +10,9 @@ #include <asm/sgialib.h> #include <asm/bootinfo.h> -/* #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 <linux/config.h> #include <linux/init.h> +#include <linux/kernel.h> #include <asm/sgialib.h> #include <asm/bcache.h> +#include <linux/console.h> +#include <linux/kdev_t.h> +#include <linux/major.h> + +#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 <linux/init.h> #include <linux/kernel.h> @@ -19,50 +17,51 @@ #include <asm/bootinfo.h> 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 <linux/init.h> #include <linux/kernel.h> @@ -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 <asm/bootinfo.h> #include <asm/system.h> -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 <linux/config.h> -#include <linux/init.h> -#include <linux/kernel.h> - -#include <asm/sgialib.h> - -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 <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: int-handler.S,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <asm/asm.h> #include <asm/mipsregs.h> #include <asm/regdef.h> #include <asm/stackframe.h> - /* 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 <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <linux/config.h> #include <linux/init.h> #include <linux/signal.h> @@ -14,6 +11,7 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/ioport.h> + #include <asm/io.h> #include <asm/irq.h> #include <asm/ptrace.h> @@ -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<<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); + /* 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 <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id$ */ - #include <linux/kernel.h> #include <linux/types.h> + #include <asm/nile4.h> - /* - * 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 <ajoshi@unixbox.com> - * - * - * Dynamic DMA mapping support. - * - * swiped from i386, and cloned for MIPS by Geert. - * - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/pci.h> -#include <asm/io.h> - -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 <geert@sonycom.com> * Albert Dorofeev <albert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $ */ - #include <linux/init.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/ioport.h> -#include <asm-mips/nile4.h> + +#include <asm/nile4.h> 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 <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: prom.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <linux/init.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/bootmem.h> + #include <asm/addrspace.h> #include <asm/bootinfo.h> -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 <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id: setup.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ - #include <linux/config.h> #include <linux/init.h> #include <linux/kbd_ll.h> @@ -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 <geert@sonycom.com> * Sony Software Development Center Europe (SDCE), Brussels - * - * $Id* */ - #include <linux/init.h> #include <asm/mc146818rtc.h> 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 <linux/config.h> + +#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 <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +/* + * 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 <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ptrace.h> +#include <asm/nile4.h> + +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 <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/kernel.h> +#include <linux/types.h> + +#include <asm/nile4.h> + + +/* + * 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 <geert@sonycom.com> + * Albert Dorofeev <albert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/ioport.h> + +#include <asm-mips/nile4.h> + + +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 <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * Jun Sun - modified for DDB5476. + */ +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> + + +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 <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/kernel.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/console.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/pc_keyb.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#include <asm/addrspace.h> +#include <asm/bcache.h> +#include <asm/keyboard.h> +#include <asm/irq.h> +#include <asm/reboot.h> +#include <asm/gdb-stub.h> +#include <asm/nile4.h> + + +#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 <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/init.h> + +#include <asm/mc146818rtc.h> + +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 <linux/config.h> + +#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 <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .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 <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/serial_reg.h> + +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_int.h> +#include <asm/it8172/it8172_dbg.h> + +#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; j<smp_num_cpus; j++) + len += sprintf(buf+len, "CPU%d ",j); + *(char *)(buf+len++) = '\n'; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_desc[i].action; + if ( !action || !action->handler ) + 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<<irq); + //printk("action->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<<irq); + enable_it8172_irq(irq); + } + else + { + spurious_count++; + printk("Unhandled interrupt %d, cause %x, disabled\n", + (unsigned)irq, (unsigned)regs->cp0_cause); + disable_it8172_irq(irq); + //disable_irq(1<<irq); + } + irq_exit(cpu, irq); +} + +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; + + /* + * IP0 and IP1 are software interrupts. IP7 is typically the timer interrupt. + * + * The ITE QED-4N-S01B board has one single interrupt line going from + * the system controller to the CPU. It's connected to the CPU external + * irq pin 1, which is IP2. The interrupt numbers are listed in it8172_int.h; + * the ISA interrupts are numbered from 0 to 15, and the rest go from + * there. + */ + + //printk("request_irq: %d handler %x\n", irq, handler); + 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; + disable_it8172_irq(irq); + //disable_irq(1<<irq); + restore_flags(flags); + kfree(action); + return 0; + } + return -ENOENT; + } + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + memset(action, 0, sizeof(struct irqaction)); + + save_flags(flags); + cli(); + + action->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<<EXT_IRQ5_TO_IP); /* timer interrupt */ +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + + +void __init init_IRQ(void) +{ + int i; + + memset(irq_desc, 0, sizeof(irq_desc)); + set_except_vector(0, it8172_IRQ); + + /* mask all interrupts */ + it8172_hw0_icregs->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<<EXT_IRQ0_TO_IP); + //change_cp0_status(ST0_IM, IE_IRQ2); + +#ifdef CONFIG_REMOTE_DEBUG + /* If local serial I/O used for debug port, enter kgdb at once */ + puts("Waiting for kgdb to connect..."); + set_debug_traps(); + breakpoint(); +#endif +} + +void mips_spurious_interrupt(struct pt_regs *regs) +{ +#if 1 + return; +#else + unsigned long status, cause; + + printk("got spurious interrupt\n"); + status = read_32bit_cp0_register(CP0_STATUS); + cause = read_32bit_cp0_register(CP0_CAUSE); + printk("status %x cause %x\n", status, cause); + printk("epc %x badvaddr %x \n", regs->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 <linux/config.h> + +#ifdef CONFIG_IT8172_CIR + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_cir.h> + + +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 <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_pci.h> + +#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 <asm/spinlock.h> +#include <linux/mc146818rtc.h> +#include <asm/it8172/it8172.h> + +#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 <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/console.h> +#include <linux/mc146818rtc.h> +#include <linux/serial_reg.h> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/it8172/it8172.h> +#include <asm/it8712.h> +#ifdef CONFIG_PC_KEYB +#include <asm/keyboard.h> +#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 <asm/io.h> +#include <asm/types.h> +#include <asm/it8712.h> +#include <asm/it8172/it8172.h> + +#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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +/* #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 <linux/types.h> + +#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 <linux/sched.h> +#include <linux/mm.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/reboot.h> +#include <asm/system.h> + +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 <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/it8172/it8172_int.h> + +#include <linux/mc146818rtc.h> +#include <linux/timex.h> + +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 <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_dbg.h> + +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 <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_pci.h> +#include <asm/it8172/it8172_int.h> + +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 <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> #include <asm/branch.h> +#include <asm/cpu.h> #include <asm/inst.h> #include <asm/ptrace.h> #include <asm/uaccess.h> +#include <asm/bootinfo.h> +#include <asm/processor.h> /* * 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 <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -21,6 +21,7 @@ #include <linux/a.out.h> #include <asm/bootinfo.h> +#include <asm/cpu.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/mipsregs.h> @@ -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 <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -24,6 +26,8 @@ #include <asm/page.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> 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 <asm/asm.h> #include <asm/bootinfo.h> @@ -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 <asm/asm.h> #include <asm/errno.h> @@ -19,7 +19,7 @@ #include <asm/regdef.h> #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 <asm/asm.h> #include <asm/current.h> #include <asm/offset.h> @@ -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 <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> @@ -24,8 +32,6 @@ #include <asm/asmmacro.h> - .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 <asm/asm.h> #include <asm/fpregdef.h> @@ -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 <linux/config.h> #include <linux/errno.h> @@ -36,10 +37,10 @@ #include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> +#include <asm/cpu.h> #include <asm/io.h> #include <asm/stackframe.h> #include <asm/system.h> -#include <asm/cpu.h> #ifdef CONFIG_SGI_IP22 #include <asm/sgialib.h> #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 <linux/config.h> #include <linux/init.h> @@ -16,12 +19,15 @@ #include <linux/smp_lock.h> #include <linux/spinlock.h> +#include <asm/bootinfo.h> #include <asm/branch.h> +#include <asm/cpu.h> #include <asm/cachectl.h> +#include <asm/inst.h> #include <asm/jazz.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/bootinfo.h> +#include <asm/siginfo.h> #include <asm/watch.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -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 <linux/config.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/pc_keyb.h> @@ -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 <linux/mm.h> +#include <linux/signal.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> + +#include <asm/asm.h> +#include <asm/branch.h> +#include <asm/byteorder.h> +#include <asm/inst.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/pgtable.h> + +#include <asm/fpu_emulator.h> + +#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 <linux/kernel.h> +#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 <linux/types.h> + +/* + * 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 <stdarg.h> +#endif + +#else + +/* Note that __KERNEL__ is taken to mean Linux kernel */ + +#if #system(OpenBSD) +#include <machine/types.h> +#endif +#include <machine/endian.h> + +#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 <linux/sched.h> +#include <asm/processor.h> +#include <asm/signal.h> +#include <asm/uaccess.h> + +#include <asm/fpu_emulator.h> + +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 <linux/kernel.h> +#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 <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> + +#include <asm/irq.h> +#include <asm/mips-boards/atlas.h> +#include <asm/mips-boards/atlasint.h> +#include <asm/gdb-stub.h> + + +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 <linux/spinlock.h> +#include <linux/mc146818rtc.h> +#include <asm/mips-boards/atlas.h> + + +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 <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/ioport.h> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/atlasint.h> + +#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 <linux/init.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +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 <asm/mips-boards/generic.h> + + +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 <linux/config.h> +#include <linux/serialP.h> +#include <linux/serial_reg.h> + +#include <asm/serial.h> +#include <asm/io.h> + +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 <asm/mips-boards/atlas.h> +#include <asm/mips-boards/saa9730_uart.h> + +#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 <linux/config.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#include <asm/io.h> +#include <asm/mips-boards/prom.h> +#include <asm/mips-boards/generic.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/malta.h> + +/* 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 <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> + +#include <asm/mips-boards/prom.h> + +/*#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 <linux/config.h> + +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +/* 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 <linux/config.h> + +#ifdef CONFIG_PCI + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mips-boards/generic.h> +#include <asm/gt64120.h> +#ifdef CONFIG_MIPS_MALTA +#include <asm/mips-boards/malta.h> +#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 <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/serialP.h> +#include <linux/serial_reg.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/serial.h> + + +#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 <linux/config.h> + +#include <asm/reboot.h> +#include <asm/mips-boards/generic.h> +#if defined(CONFIG_MIPS_ATLAS) +#include <asm/mips-boards/atlas.h> +#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 <linux/config.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/div64.h> + +#include <linux/mc146818rtc.h> +#include <linux/timex.h> + +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> + +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 <linux/init.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/random.h> + +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/mips-boards/malta.h> +#include <asm/mips-boards/maltaint.h> +#include <asm/mips-boards/piix4.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/generic.h> + +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 <linux/spinlock.h> +#include <linux/mc146818rtc.h> +#include <asm/mips-boards/malta.h> + +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 <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#ifdef CONFIG_BLK_DEV_IDE +#include <linux/ide.h> +#endif + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> +#include <asm/mips-boards/malta.h> +#include <asm/mips-boards/maltaint.h> +#ifdef CONFIG_BLK_DEV_FD +#include <asm/floppy.h> +#endif +#include <asm/dma.h> + +#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 <cort@fsmlabs.com> -# - -.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 <asm/asm.h> -#include <asm/mipsregs.h> -#include <asm/regdef.h> -#include <asm/stackframe.h> - - .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 <cort@fsmlabs.com> - */ -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> -#include <linux/slab.h> -#include <linux/random.h> - -#include <asm/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> -#include <asm/system.h> -#include <asm/orion.h> - -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; j<smp_num_cpus; j++) - len += sprintf(buf+len, "CPU%d ",j); - *(char *)(buf+len++) = '\n'; - - for (i = 0 ; i < NR_IRQS ; i++) { - action = irq_desc[i].action; - if ( !action || !action->handler ) - 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 <linux/config.h> -#include <linux/errno.h> -#include <linux/hdreg.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/utsname.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#ifdef CONFIG_BLK_DEV_RAM -#include <linux/blk.h> -#endif -#include <linux/ide.h> -#ifdef CONFIG_RTC -#include <linux/timex.h> -#endif - -#include <asm/asm.h> -#include <asm/bootinfo.h> -#include <asm/cachectl.h> -#include <asm/io.h> -#include <asm/stackframe.h> -#include <asm/system.h> -#include <asm/cpu.h> -#include <linux/bootmem.h> -#include <asm/addrspace.h> -#include <asm/mc146818rtc.h> - -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 <stdio.h> -#include <unistd.h> - -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 <in-file >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 <linux/tty.h> -#include <linux/major.h> -#include <linux/ptrace.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/fs.h> -/* -#include <asm/sgialib.h> -*/ -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 <linux/config.h> -#include <linux/errno.h> -#include <linux/hdreg.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/utsname.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/interrupt.h> -#ifdef CONFIG_BLK_DEV_RAM -#include <linux/blk.h> -#endif -#include <linux/ide.h> -#ifdef CONFIG_RTC -#include <linux/timex.h> -#endif - -#include <asm/asm.h> -#include <asm/bootinfo.h> -#include <asm/cachectl.h> -#include <asm/io.h> -#include <asm/stackframe.h> -#include <asm/system.h> -#include <asm/cpu.h> -#include <linux/bootmem.h> -#include <asm/addrspace.h> -#include <asm/mc146818rtc.h> -#include <asm/orion.h> - -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/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 <ajoshi@unixbox.com> - * based on alpha port by Andrea Arcangeli <andrea@suse.de> - */ - -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 <linux/kernel.h> #include <linux/string.h> #include <asm/ebcdic.h> +#include <asm/cpcmd.h> 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 <linux/kernel.h> #include <linux/errno.h> #include <linux/malloc.h> -#include <linux/vmalloc.h> #include <linux/ctype.h> #include <linux/version.h> #include <asm/uaccess.h> #include <asm/semaphore.h> -#ifdef MODULE #include <linux/module.h> -#endif #include <asm/debug.h> #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;idx<numargs;idx++) + curr_event->args[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;idx<numargs;idx++) + curr_event->args[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 <peschke@fh-brandenburg.de> */ +#include <linux/module.h> #include <asm/types.h> /* @@ -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 <linux/sys.h> #include <linux/linkage.h> #include <linux/config.h> #include <asm/lowcore.h> #include <asm/errno.h> -#define ASSEMBLY #include <asm/smp.h> -#include <asm/s390-regs-common.h> - +#include <asm/ptrace.h> /* - * 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 <linux/module.h> #include <linux/config.h> #include <linux/ptrace.h> #include <linux/errno.h> @@ -20,7 +21,7 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/timex.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/string.h> #include <linux/random.h> #include <linux/smp.h> @@ -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<asm/irqextras390.h> -#include<asm/lowcore.h> - -#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 <linux/config.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/ptrace.h> - -#include <asm/uaccess.h> -#include <asm/mathemu.h> - -#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 <asm/system.h> #include <asm/io.h> #include <asm/processor.h> -#include <asm/misc390.h> #include <asm/irq.h> 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(useraddr<sizeof(user_regs_struct)) + else if(useraddr<sizeof(struct user_regs_struct)) { - copymax=sizeof(user_regs_struct); + copymax=sizeof(struct user_regs_struct); realuseraddr=(addr_t)&(((u8 *)&task->thread.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 <linux/module.h> #include <linux/kernel.h> #include <linux/malloc.h> #include <asm/lowcore.h> @@ -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 <linux/config.h> #include <linux/module.h> -#include <linux/string.h> -#include <asm/ccwcache.h> -#include <asm/debug.h> -#include <asm/irq.h> -#include <asm/s390_ext.h> -#include <asm/s390dyn.h> -#include <asm/ebcdic.h> #include <asm/checksum.h> #include <asm/delay.h> -#if CONFIG_CHANDEV -#include <asm/chandev.h> -#endif +#include <asm/setup.h> #if CONFIG_IP_MULTICAST #include <net/arp.h> #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 <asm/smplock.h> -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 <asm/system.h> #include <asm/smp.h> #include <asm/mmu_context.h> +#include <asm/cpcmd.h> /* * 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 <linux/module.h> #include <linux/init.h> #include <linux/mm.h> @@ -33,8 +34,7 @@ #include <asm/pgalloc.h> #include <asm/irq.h> #include <asm/s390_ext.h> - -#include "cpcmd.h" +#include <asm/cpcmd.h> /* 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 <asm/gdb-stub.h> #endif +#include <asm/cpcmd.h> /* 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 <linux/module.h> +#include <linux/kernel.h> + +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 <linux/config.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/uaccess.h> + +#include "sfp-util.h" +#include <math-emu/soft-fp.h> +#include <math-emu/single.h> +#include <math-emu/double.h> +#include <math-emu/quad.h> + +/* + * 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 <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <asm/byteorder.h> + +#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 <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/compatmac.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -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 Wed Apr 11 19:02:27 2001 @@ -35,27 +35,13 @@ #include <asm/pgalloc.h> #include <asm/dma.h> #include <asm/lowcore.h> +#include <asm/tlb.h> -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. - */ +static unsigned long totalram_pages; pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); -char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); -pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -84,53 +70,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<PTRS_PER_PTE;i++) - pte_clear(pte++); -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - unsigned long pte; - - pte = (unsigned long) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - invalidate_page((pte_t*) pte); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072; - return (pte_t *) pte + offset; - } - pte = (unsigned long) get_bad_pte_table(); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072; - return NULL; - } - free_page(pte); - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -139,9 +78,9 @@ if(pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed += 2; if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed++; if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++; } while(pgtable_cache_size > low); } return freed; 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, <utz.bacher@de.ibm.com> * * Device-in-use-checks by Fritz Elfert, <felfert@to.com> + * Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com> * * 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 <label>] [-b <blocksize>] [<range>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \ "<diskspec>\n\n",prog_name); #else /* RANGE_FORMATTING */ - printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \ "<diskspec>\n\n",prog_name); #endif /* RANGE_FORMATTING */ printf(" -t means testmode\n"); printf(" -v means verbose mode\n"); + printf(" -C means format compatible disk layout\n"); printf(" -V means print version\n"); printf(" -L means don't write disk label\n"); printf(" <label> is a label which is converted to EBCDIC and " \ @@ -200,7 +202,7 @@ /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -218,7 +220,8 @@ fclose(file); ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \ - "filesystem (are you sure to have the right param line?)\n", + "filesystem (are you sure to have the right parameter " \ + "dasd=xxx?)\n", prog_name); } @@ -488,14 +491,14 @@ } check_mounted(major_no, minor_no); + get_xno_from_xno(&devno,&major_no,&minor_no, + GIVEN_MAJOR|GIVEN_MINOR); if ((!writenolabel) && (!labelspec)) { sprintf(label,"LNX1 x%04x",devno); } if ( ((withoutprompt)&&(verbosity>=1)) || (!withoutprompt) ) { - get_xno_from_xno(&devno,&major_no,&minor_no, - GIVEN_MAJOR|GIVEN_MINOR); printf("\nI am going to format the device %s in the " \ "following way:\n",dev_name); printf(" Device number of device : 0x%x\n",devno); @@ -505,6 +508,9 @@ "no":"yes"); if (!writenolabel) printf(" Disk label : %s\n",label); + if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY) + printf(" Compatible Disk Layout : %s\n",(format_params.intensity&0x08)? + "yes":"no"); #ifdef RANGE_FORMATTING printf(" Start track : %d\n" \ ,format_params.start_unit); @@ -558,7 +564,7 @@ } - rc=ioctl(fd,BLKGETSIZE,&new_blksize); + rc=ioctl(fd,BLKSSZGET,&new_blksize); if (rc) { ERRMSG("%s: the ioctl call to get blocksize " \ "returned with the following error " \ @@ -664,9 +670,9 @@ opterr=0; #ifdef RANGE_FORMATTING - while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) { #endif /* RANGE_FORMATTING */ - while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) { switch (oc) { case 'y': withoutprompt=1; @@ -686,6 +692,9 @@ case 'h': exit_usage(0); + case 'C': + format_params.intensity&=0x08; + break; case 'V': printf("%s version 0.99\n",prog_name); diff -u --recursive --new-file v2.4.3/linux/arch/s390/tools/silo/silo.c linux/arch/s390/tools/silo/silo.c --- v2.4.3/linux/arch/s390/tools/silo/silo.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/tools/silo/silo.c Wed Apr 11 19:02:27 2001 @@ -9,6 +9,9 @@ * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com> * Fritz Elfert <felfert@to.com> contributed support for * /etc/silo.conf based on Intel's lilo + * Changes : + * 01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com> + * adapted to deal with devices and bootsects of various sizes */ #include <stddef.h> @@ -376,7 +379,7 @@ if ( errno == ENOENT ) { ITRY (creat ( o-> bootmap, O_RDWR )); } else { - PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap, + PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap, strerror(errno)); } } @@ -482,6 +485,7 @@ int bs, boots; char *tmpdev; char buffer[4096]={0,}; + int blocksize, sectsize; ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC)); ITRY (fstat (d_fd, &d_st)); ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC)); @@ -508,6 +512,7 @@ NTRY ( tmpdev = tmpnam(NULL) ); ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev)); ITRY (bd_fd = open (tmpdev, O_RDONLY)); + ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize)); ITRY (ioctl(s_fd,FIBMAP,&boots)); ITRY (ioctl (bd_fd, BIODASDRWTB, &boots)); PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots); @@ -515,13 +520,21 @@ close(s_fd); ITRY (unlink(tmpdev)); /* Now patch the bootsector */ + ITRY (stat (o->bootsect, &b_st)); + if ((sectsize = b_st.st_size) > blocksize ) + { + ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize); + rc = -1; + errno = EINVAL; + } ITRY (b_fd = open (o->bootsect, O_RDONLY)); - NTRY (read (b_fd, buffer, 4096)); + ITRY (read (b_fd, buffer, sectsize)); memset (buffer + 0xe0, 0, 8); *(int *) (buffer + 0xe0) = boots; if ( o -> testlevel <= 0 ) { - NTRY (write (d_fd, buffer, 4096)); - NTRY (write (d_fd, buffer, 4096)); + ITRY (write (d_fd, buffer, sectsize)); + ITRY (lseek (d_fd, blocksize, SEEK_SET)); + ITRY (write (d_fd, buffer, sectsize)); } close (b_fd); close (d_fd); diff -u --recursive --new-file v2.4.3/linux/arch/s390x/boot/Makefile linux/arch/s390x/boot/Makefile --- v2.4.3/linux/arch/s390x/boot/Makefile Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/boot/Makefile Wed Apr 11 19:02:29 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/s390x/config.in linux/arch/s390x/config.in --- v2.4.3/linux/arch/s390x/config.in Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/config.in Tue Apr 17 17:19:25 2001 @@ -6,6 +6,8 @@ define_bool CONFIG_ISA n define_bool CONFIG_EISA n define_bool CONFIG_MCA n +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 @@ -47,12 +49,13 @@ 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 endmenu + source drivers/s390/Config.in if [ "$CONFIG_NET" = "y" ]; then @@ -68,6 +71,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/s390x/defconfig linux/arch/s390x/defconfig --- v2.4.3/linux/arch/s390x/defconfig Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/defconfig Wed Apr 11 19:02:29 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 @@ -37,6 +37,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 @@ -50,9 +51,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) @@ -64,20 +70,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 @@ -89,6 +106,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 @@ -110,11 +131,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 @@ -139,6 +165,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 @@ -193,8 +221,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 @@ -212,8 +238,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/s390x/kernel/Makefile linux/arch/s390x/kernel/Makefile --- v2.4.3/linux/arch/s390x/kernel/Makefile Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/Makefile Wed Apr 11 19:02:29 2001 @@ -14,7 +14,7 @@ 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 diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/binfmt_elf32.c linux/arch/s390x/kernel/binfmt_elf32.c --- v2.4.3/linux/arch/s390x/kernel/binfmt_elf32.c Mon Mar 19 12:35:11 2001 +++ linux/arch/s390x/kernel/binfmt_elf32.c Wed Apr 11 19:02:29 2001 @@ -23,7 +23,8 @@ * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(x) \ - ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) /* ELF register definitions */ #define NUM_GPRS 16 diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/cpcmd.c linux/arch/s390x/kernel/cpcmd.c --- v2.4.3/linux/arch/s390x/kernel/cpcmd.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/cpcmd.c Wed Apr 11 19:02:29 2001 @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <asm/ebcdic.h> +#include <asm/cpcmd.h> void cpcmd(char *cmd, char *response, int rlen) { diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/cpcmd.h linux/arch/s390x/kernel/cpcmd.h --- v2.4.3/linux/arch/s390x/kernel/cpcmd.h Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/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/s390x/kernel/cpprintk.c linux/arch/s390x/kernel/cpprintk.c --- v2.4.3/linux/arch/s390x/kernel/cpprintk.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/cpprintk.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -#include "cpcmd.h" -#include <linux/mm.h> -#include <linux/tty_driver.h> -#include <linux/smp_lock.h> -#include <linux/console.h> -#include <linux/init.h> - -#include <asm/uaccess.h> - -static char buf[1024]; - -asmlinkage int s390printk(const char *fmt, ...) -{ - va_list args; - int i; - unsigned long flags; - spin_lock_irqsave(&console_lock, flags); - va_start(args, fmt); - i = vsprintf(&buf[0],"MSG * ",args); - i = vsprintf(&buf[i], fmt, args); - va_end(args); - cpcmd(buf,0,0); - spin_unlock_irqrestore(&console_lock, flags); - return i; -} diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/debug.c linux/arch/s390x/kernel/debug.c --- v2.4.3/linux/arch/s390x/kernel/debug.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/debug.c Wed Apr 11 19:02:29 2001 @@ -15,45 +15,53 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/malloc.h> -#include <linux/vmalloc.h> #include <linux/ctype.h> #include <linux/version.h> #include <asm/uaccess.h> #include <asm/semaphore.h> -#ifdef MODULE #include <linux/module.h> -#endif #include <asm/debug.h> #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;idx<numargs;idx++) + curr_event->args[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;idx<numargs;idx++) + curr_event->args[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/s390x/kernel/ebcdic.c linux/arch/s390x/kernel/ebcdic.c --- v2.4.3/linux/arch/s390x/kernel/ebcdic.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/ebcdic.c Wed Apr 11 19:02:29 2001 @@ -9,6 +9,7 @@ * Martin Peschke <peschke@fh-brandenburg.de> */ +#include <linux/module.h> #include <asm/types.h> /* @@ -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/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S --- v2.4.3/linux/arch/s390x/kernel/entry.S Fri Mar 2 11:12:06 2001 +++ linux/arch/s390x/kernel/entry.S Wed Apr 11 19:02:29 2001 @@ -9,56 +9,53 @@ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), */ +#define ASSEMBLY + #include <linux/sys.h> #include <linux/linkage.h> #include <linux/config.h> #include <asm/lowcore.h> #include <asm/errno.h> -#define ASSEMBLY #include <asm/smp.h> -#include <asm/s390-regs-common.h> +#include <asm/ptrace.h> /* - * 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 */ @@ -72,6 +69,8 @@ _TSS_ERROR = (_TSS_PROT+8) _TSS_TRAP = (_TSS_ERROR+4) _TSS_PER = (_TSS_TRAP+4) +_TSS_IEEE = (_TSS_PER+72) +_TSS_FLAGS = (_TSS_IEEE+8) /* * these are offsets into the task-struct. @@ -83,31 +82,6 @@ tsk_ptrace = 40 processor = 100 -/* PSW related defines */ -disable = 0xFC -enable = 0x03 -daton = 0x04 - - -#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 - lg %r0,SP_PSW+8(%r15) - sllg %r0,%r0,1 - chi %r0,0 - jnz sysc_dn - la %r2,sysc_msg-sysc_lit(%r13) - lgr %r3,%r15 - brasl %r14,sysc_printk -sysc_dn: -#endif - /* * Register usage in interrupt handlers: * R9 - pointer to current task structure @@ -116,38 +90,41 @@ * R15 - kernel stack pointer */ -#define SAVE_ALL(psworg) \ - stmg %r14,%r15,__LC_SAVE_AREA ; \ - stam %a2,%a4,__LC_SAVE_AREA+16 ; \ - tm psworg+1,0x01 ; /* test problem state bit */ \ - jz 0f ; /* skip stack setup save */ \ - lg %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \ - slr %r14,%r14 ; \ - sar %a2,%r14 ; /* set ac.reg. 2 to primary space */ \ - lhi %r14,1 ; \ - sar %a4,%r14 ; /* set access reg. 4 to home space */ \ -0: aghi %r15,-SP_SIZE ; /* make room for registers & psw */ \ - nill %r15,0xfff8 ; /* align stack pointer to 8 */ \ - stmg %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \ - stg %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \ - mvc SP_RE(16,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \ - stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\ - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 ; /* store ac. regs */ \ - mvc SP_PSW(16,%r15),psworg; /* move user PSW to stack */ \ - lhi %r0,psworg ; /* store trap indication */ \ - st %r0,SP_TRAP(%r15) ; \ - xc 0(8,%r15),0(%r15) ; /* clear back chain */ - -#define RESTORE_ALL \ - mvc __LC_RETURN_PSW(16),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ - lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lmg %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ - lpswe __LC_RETURN_PSW /* back to caller */ + .macro SAVE_ALL psworg # system entry macro + stmg %r14,%r15,__LC_SAVE_AREA + stam %a2,%a4,__LC_SAVE_AREA+16 + tm \psworg+1,0x01 # test problem state bit + jz 0f # skip stack setup save + lg %r15,__LC_KERNEL_STACK # problem state -> load ksp + slr %r14,%r14 + sar %a2,%r14 # set ac.reg. 2 to primary space + lhi %r14,1 + sar %a4,%r14 # set access reg. 4 to home space +0: aghi %r15,-SP_SIZE # make room for registers & psw + nill %r15,0xfff8 # align stack pointer to 8 + stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack + stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs + mvc SP_PSW(16,%r15),\psworg # move user PSW to stack + lhi %r0,\psworg # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(8,%r15),0(%r15) # clear back chain + .endm + + .macro RESTORE_ALL # system exit macro + mvc __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore + lam %a0,%a15,SP_AREGS(%r15) # load the access registers + lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + ni __LC_RETURN_PSW+1,0xfd # clear wait state bit + lpswe __LC_RETURN_PSW # back to caller + .endm -#define GET_CURRENT /* load pointer to task_struct to R9 */ \ - lghi %r9,-16384 ; \ + .macro GET_CURRENT + lghi %r9,-16384 # load pointer to task_struct to %r9 ngr %r9,15 + .endm /* @@ -162,7 +139,7 @@ lg %r4,_TSS_PTREGS(%r3) tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? jz resume_noper # if not we're fine - stctg %r9,%r11,48(%r15) # We are using per stuff + stctg %c9,%c11,48(%r15) # We are using per stuff clc _TSS_PER(24,%r3),48(%r15) je resume_noper # we got away without bashing TLB's lctlg %c9,%c11,_TSS_PER(%r3) # Nope we didn't @@ -191,10 +168,11 @@ .globl system_call system_call: - SAVE_ALL(__LC_SVC_OLD_PSW) - 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: - larl %r1,sys_call_table + GET_CURRENT # load pointer to task_struct to R9 + larl %r7,sys_call_table llgc %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore stosm 48(%r15),0x03 # reenable interrupts sll %r8,3 @@ -202,8 +180,7 @@ jo sysc_noemu la %r8,4(%r8) # use 31 bit emulation system calls sysc_noemu: - GET_CURRENT # load pointer to task_struct to R9 - lgf %r8,0(%r8,%r1) # load address of system call routine + lgf %r8,0(%r8,%r7) # load address of system call routine tm tsk_ptrace+7(%r9),0x02 # PT_TRACESYS jnz sysc_tracesys basr %r14,%r8 # call sys_xxxx @@ -212,7 +189,6 @@ # changing anything here !! sysc_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? jno sysc_leave # no-> skip bottom half, resched & signal # @@ -228,12 +204,12 @@ lg %r0,need_resched(%r9) # get need_resched from task_struct ltgr %r0,%r0 jnz sysc_reschedule - icm %r0,15,sigpending(%r9) # get sigpending from task_struct + icm %r0,15,sigpending(%r9) # get sigpending from task_struct jnz sysc_signal_return sysc_leave: - icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct - jnz pgm_svcret - stnsm 48(%r15),disable # disable I/O and ext. interrupts + tm SP_PGM_OLD_ILC(%r15),0xff + jz pgm_svcret + stnsm 48(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -667,7 +643,7 @@ je pgm_svcper # no interesting special case, ignore PER event lm %r13,%r15,__LC_SAVE_AREA - lpsw __LC_PGM_OLD_PSW + lpswe __LC_PGM_OLD_PSW # it was a single stepped SVC that is causing all the trouble pgm_svcper: tm __LC_SVC_OLD_PSW+1,0x01 # test problem state bit @@ -681,7 +657,7 @@ nill %r15,0xfff8 # align stack pointer to 8 stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_RE(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack + mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack @@ -689,14 +665,13 @@ st %r0,SP_TRAP(%r15) xc 0(8,%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 j pgm_system_call # now do the svc pgm_svcret: lhi %r0,__LC_PGM_OLD_PSW # set trap indication back to pgm_chk st %r0,SP_TRAP(%r15) llgh %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 j pgm_no_sv pgm_sv: tm __LC_PGM_OLD_PSW+1,0x01 # test problem state bit @@ -710,15 +685,16 @@ nill %r15,0xfff8 # align stack pointer to 8 stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_RE(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack + mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack lhi %r0,__LC_PGM_OLD_PSW # store trap indication st %r0,SP_TRAP(%r15) xc 0(8,%r15),0(%r15) # clear back chain - xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - llgh %r7,__LC_PGM_ILC # load instruction length + mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid + llgh %r7,__LC_PGM_ILC # load instruction length + GET_CURRENT pgm_no_sv: llgh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it stosm 48(%r15),0x03 # reenable interrupts @@ -726,8 +702,8 @@ nr %r3,%r8 # clear per-event-bit & move to r3 je pgm_dn # none of Martins exceptions occurred bypass sll %r3,3 - larl %r9,pgm_check_table - lg %r9,0(%r3,%r9) # load address of handler routine + larl %r1,pgm_check_table + lg %r1,0(%r3,%r1) # load address of handler routine srl %r3,3 la %r2,SP_PTREGS(%r15) # address of register-save area chi %r3,0x4 # protection-exception ? @@ -735,7 +711,7 @@ lg %r5,SP_PSW+8(15) # load psw addr slgr %r5,%r7 # substract ilc from psw stg %r5,SP_PSW+8(15) # store corrected psw addr -pgm_go: basr %r14,%r9 # branch to interrupt-handler +pgm_go: basr %r14,%r1 # branch to interrupt-handler pgm_dn: nill %r8,0x80 # check for per exception je sysc_return la %r2,SP_PTREGS(15) # address of register-save area @@ -747,17 +723,17 @@ */ .globl io_int_handler io_int_handler: - SAVE_ALL(__LC_IO_OLD_PSW) + 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 llgh %r3,__LC_SUBCHANNEL_NR # load subchannel number - llgf %r4,__LC_IO_INT_PARM # load interruption parm - llgf %r5,__LC_IO_INT_WORD # load interruption word + llgf %r4,__LC_IO_INT_PARM # load interuption parm + llgf %r5,__LC_IO_INT_WORD # load interuption word brasl %r14,do_IRQ # call standard irq handler io_return: - GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - jz io_leave # no-> skip resched & signal + jno io_leave # no-> skip resched & signal stosm 48(%r15),0x03 # reenable interrupts # # check, if bottom-half has to be done @@ -775,7 +751,7 @@ icm %r0,15,sigpending(%r9) # get sigpending from task_struct jnz io_signal_return io_leave: - stnsm 48(%r15),disable # disable I/O and ext. interrupts + stnsm 48(%r15),0xfc # disable I/O and ext. interrupts RESTORE_ALL # @@ -807,34 +783,35 @@ */ .globl ext_int_handler ext_int_handler: - SAVE_ALL(__LC_EXT_OLD_PSW) + 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 llgh %r3,__LC_EXT_INT_CODE # error code lgr %r1,%r3 # calculate index = code & 0xff nill %r1,0xff sll %r1,3 - larl %r9,ext_int_hash - lg %r9,0(%r1,%r9) # get first list entry for hash value - ltgr %r9,%r9 # == NULL ? + larl %r4,ext_int_hash + lg %r4,0(%r1,%r4) # get first list entry for hash value + ltgr %r4,%r4 # == NULL ? jz io_return # yes, nothing to do, exit ext_int_loop: - ch %r3,16(%r9) # compare external interrupt code + ch %r3,16(%r4) # compare external interrupt code je ext_int_found - lg %r9,0(%r9) # next list entry - ltgr %r9,%r9 + lg %r4,0(%r4) # next list entry + ltgr %r4,%r4 jnz ext_int_loop j io_return ext_int_found: - lg %r9,8(%r9) # get handler address + lg %r4,8(%r4) # get handler address larl %r14,io_return - br %r9 # branch to ext call handler + br %r4 # branch to ext call handler /* * Machine check handler routines */ .globl mcck_int_handler mcck_int_handler: - SAVE_ALL(__LC_MCK_OLD_PSW) + SAVE_ALL __LC_MCK_OLD_PSW brasl %r14,s390_do_machine_check mcck_return: RESTORE_ALL @@ -848,7 +825,7 @@ lg %r15,__LC_KERNEL_STACK # load ksp lctlg %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 lmg %r6,%r15,48(%r15) # load registers from clone jg start_secondary #else diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/exec32.c linux/arch/s390x/kernel/exec32.c --- v2.4.3/linux/arch/s390x/kernel/exec32.c Thu Mar 22 09:25:21 2001 +++ linux/arch/s390x/kernel/exec32.c Wed Apr 11 19:02:29 2001 @@ -82,3 +82,4 @@ return 0; } +EXPORT_SYMBOL(setup_arg_pages32); diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S --- v2.4.3/linux/arch/s390x/kernel/head.S Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/head.S Wed Apr 11 19:02:29 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+4-PARMAREA(%r12) # # load parameter file from ipl device @@ -405,16 +406,18 @@ sr %r3,%r2 la %r3,1(%r3) .done: - st %r3,MEMORY_SIZE-PARMAREA(%r11) + l %r1,.memsize + st %r3,4(%r1) slr %r0,%r0 - st %r0,INITRD_SIZE-PARMAREA(%r11) - st %r0,INITRD_START-PARMAREA(%r11) + st %r0,INITRD_SIZE+4-PARMAREA(%r11) + st %r0,INITRD_START+4-PARMAREA(%r11) j startup # continue with startup .tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer .parm: .long PARMAREA .fourmeg: .long 0x00400000 # 4M .pgmnw: .long 0x00080000,.pgmx +.memsize: .long memory_size .lowcase: .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f @@ -480,21 +483,35 @@ bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: ng %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M - stg %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size + lg %r2,.Lmemsize-.LPG1(%r13) # address of variable memory_size + stg %r1,0(%r2) # store memory size + + lg %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+7-PARMAREA(%r12),1 # set VM flag + oi 7(%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+7-PARMAREA(%r12),4 # set P/390 flag + oi 7(%r12),4 # set P/390 flag .Lnop390: +# +# find out if we have the MVPG instruction +# + mvc __LC_PGM_NEW_PSW(16),.Lpcmvpg-.LPG1(%r13) + sgr %r0,%r0 + lghi %r1,0 + lghi %r2,0 + mvpg %r1,%r2 # Test CSP instruction + oi 7(%r12),16 # set MVPG flag +.Lchkmvpg: + lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 16 @@ -516,24 +533,23 @@ .quad 0xc0000000 # cr14: machine check handling off .quad 0 # cr15: linkage stack operations .Lpcmem:.quad 0x0000000180000000,.Lchkmem +.Lpcmvpg:.quad 0x0000000180000000,.Lchkmvpg .Lflt0: .double 0 .Lparm1:.quad PARMAREA .Lhighoff:.long 0x7fffffff .L4malign:.quad 0xffffffffffc00000 .Lbigmem:.quad 0x04000000 .Lmaxchunk:.quad 0x00ffffff +.Lmemsize:.quad memory_size +.Lmflags:.quad machine_flags # # params at 10400 (setup.h) # .org PARMAREA - .quad 0x0100 # ORIG_ROOT_DEV: ramdisk major/minor - .word 0 # MOUNT_ROOT_RDONLY: no - .quad 0 # MEMORY_SIZE - .quad 0 # MACHINE_FLAGS (bit 0:VM) + .quad 0 # IPL_DEVICE .quad RAMDISK_ORIGIN # INITRD_START .quad RAMDISK_SIZE # INITRD_SIZE - .word 0 # RAMDISK_FLAGS .org COMMAND_LINE .byte "root=/dev/ram0 ro" diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/irq.c linux/arch/s390x/kernel/irq.c --- v2.4.3/linux/arch/s390x/kernel/irq.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/irq.c Wed Apr 11 19:02:29 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 <linux/module.h> #include <linux/config.h> #include <linux/ptrace.h> #include <linux/errno.h> @@ -351,48 +352,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) { @@ -421,3 +380,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/s390x/kernel/irqextras390.c linux/arch/s390x/kernel/irqextras390.c --- v2.4.3/linux/arch/s390x/kernel/irqextras390.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/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<asm/irqextras390.h> -#include<asm/lowcore.h> - -#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/s390x/kernel/process.c linux/arch/s390x/kernel/process.c --- v2.4.3/linux/arch/s390x/kernel/process.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/process.c Wed Apr 11 19:02:29 2001 @@ -28,7 +28,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/user.h> #include <linux/a.out.h> @@ -42,7 +42,6 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/processor.h> -#include <asm/misc390.h> #include <asm/irq.h> spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; @@ -300,12 +299,10 @@ unsigned long fprs[2]; /* fpr 4 and 6 */ unsigned long empty[2]; #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 *) (4*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) | _REGION_TABLE; diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/ptrace.c linux/arch/s390x/kernel/ptrace.c --- v2.4.3/linux/arch/s390x/kernel/ptrace.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/ptrace.c Wed Apr 11 19:02:29 2001 @@ -153,7 +153,7 @@ useraddr = 2 * useraddr + sizeof(addr_t) / 2; else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0)) useraddr = useraddr + PT_ACR0 / 2; - else if(useraddr < PT_ACR0 / 2 + (sizeof(user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0)) + else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0)) useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; } #endif @@ -174,15 +174,15 @@ { copymax=PT_PSWMASK; } - else if(useraddr<(PT_PSWMASK+PSW_MASK_SIZE)) + else if(useraddr<(PT_PSWMASK+8)) { - copymax=(PT_PSWMASK+PSW_MASK_SIZE); + copymax=(PT_PSWMASK+8); if(writingtouser) mask=PSW_MASK_DEBUGCHANGE; } - else if(useraddr<(PT_PSWADDR+PSW_ADDR_SIZE)) + else if(useraddr<(PT_PSWADDR+8)) { - copymax=PT_PSWADDR+PSW_ADDR_SIZE; + copymax=PT_PSWADDR+8; mask=PSW_ADDR_DEBUGCHANGE; } else @@ -194,9 +194,9 @@ copymax=(PT_FPR15+sizeof(freg_t)); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } - else if(useraddr<sizeof(user_regs_struct)) + else if(useraddr<sizeof(struct user_regs_struct)) { - copymax=sizeof(user_regs_struct); + copymax=sizeof(struct user_regs_struct); realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); } else diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/s390_ext.c linux/arch/s390x/kernel/s390_ext.c --- v2.4.3/linux/arch/s390x/kernel/s390_ext.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/s390_ext.c Wed Apr 11 19:02:29 2001 @@ -7,6 +7,7 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/malloc.h> #include <asm/lowcore.h> @@ -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/s390x/kernel/s390_ksyms.c linux/arch/s390x/kernel/s390_ksyms.c --- v2.4.3/linux/arch/s390x/kernel/s390_ksyms.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/s390_ksyms.c Wed Apr 11 19:02:29 2001 @@ -4,71 +4,18 @@ * S390 version */ #include <linux/config.h> -#include <linux/module.h> -#include <linux/string.h> #include <linux/highuid.h> -#include <asm/ccwcache.h> -#include <asm/debug.h> -#include <asm/irq.h> -#include <asm/s390_ext.h> -#include <asm/s390dyn.h> -#include <asm/ebcdic.h> +#include <linux/module.h> +#include <linux/mm.h> #include <asm/checksum.h> #include <asm/delay.h> #include <asm/pgalloc.h> -#include <asm/idals.h> -#if CONFIG_CHANDEV -#include <asm/chandev.h> -#endif +#include <asm/setup.h> #if CONFIG_IP_MULTICAST #include <net/arp.h> #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); @@ -94,6 +41,7 @@ EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strcmp); +EXPORT_SYMBOL_NOVERS(strcat); EXPORT_SYMBOL_NOVERS(strncat); EXPORT_SYMBOL_NOVERS(strncmp); EXPORT_SYMBOL_NOVERS(strncpy); @@ -102,56 +50,22 @@ 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); - /* * binfmt_elf loader */ -EXPORT_SYMBOL(get_pte_slow); -EXPORT_SYMBOL(get_pmd_slow); extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs); EXPORT_SYMBOL(dump_fpu); -#ifdef CONFIG_S390_SUPPORT -extern int setup_arg_pages32(struct linux_binprm *bprm); -EXPORT_SYMBOL(setup_arg_pages32); -#endif EXPORT_SYMBOL(overflowuid); EXPORT_SYMBOL(overflowgid); /* * misc. */ -EXPORT_SYMBOL(module_list); +EXPORT_SYMBOL(machine_flags); EXPORT_SYMBOL(__udelay); -#ifdef CONFIG_SMP -#include <asm/smplock.h> -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); -#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 gigibit ethernet multicast support */ EXPORT_SYMBOL(arp_mc_map); #endif -EXPORT_SYMBOL(s390_daemonize); -EXPORT_SYMBOL (set_normalized_cda); - diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/semaphore.c linux/arch/s390x/kernel/semaphore.c --- v2.4.3/linux/arch/s390x/kernel/semaphore.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/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/s390x/kernel/setup.c linux/arch/s390x/kernel/setup.c --- v2.4.3/linux/arch/s390x/kernel/setup.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/setup.c Wed Apr 11 19:02:29 2001 @@ -21,7 +21,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/tty.h> @@ -38,10 +38,13 @@ #include <asm/system.h> #include <asm/smp.h> #include <asm/mmu_context.h> +#include <asm/cpcmd.h> /* * 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 @@ -205,18 +199,9 @@ "We are running under VM\n" : "We are running native\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 - /* nasty stuff with PARMAREAs. we use head.S or parameterline - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; - */ + ROOT_DEV = to_kdev_t(0x0100); memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ - memory_end = MEMORY_SIZE; /* detected in head.s */ + 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; @@ -303,9 +288,6 @@ * bootmem allocator with an invalid RAM area. */ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); - - - #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START) { diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/signal.c linux/arch/s390x/kernel/signal.c --- v2.4.3/linux/arch/s390x/kernel/signal.c Fri Feb 16 16:02:35 2001 +++ linux/arch/s390x/kernel/signal.c Wed Apr 11 19:02:29 2001 @@ -188,7 +188,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); @@ -203,7 +203,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 */ @@ -219,7 +219,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; @@ -562,6 +562,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/s390x/kernel/signal32.c linux/arch/s390x/kernel/signal32.c --- v2.4.3/linux/arch/s390x/kernel/signal32.c Fri Feb 16 16:02:35 2001 +++ linux/arch/s390x/kernel/signal32.c Wed Apr 11 19:02:29 2001 @@ -343,7 +343,7 @@ } static int -restore_sigcontext32(struct sigcontext32 *sc, pt_regs *regs, +restore_sigcontext32(struct sigcontext32 *sc, struct pt_regs *regs, _sigregs32 *sregs,sigset_t *set) { unsigned int err; diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c --- v2.4.3/linux/arch/s390x/kernel/smp.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/smp.c Wed Apr 11 19:02:29 2001 @@ -20,6 +20,7 @@ * cpu_number_map in other architectures. */ +#include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> @@ -33,8 +34,7 @@ #include <asm/pgalloc.h> #include <asm/irq.h> #include <asm/s390_ext.h> - -#include "cpcmd.h" +#include <asm/cpcmd.h> /* prototypes */ extern int cpu_idle(void * unused); @@ -392,7 +392,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) */ @@ -574,7 +574,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); } @@ -758,3 +758,8 @@ } } +EXPORT_SYMBOL(lowcore_ptr); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_num_cpus); diff -u --recursive --new-file v2.4.3/linux/arch/s390x/kernel/sys_s390.c linux/arch/s390x/kernel/sys_s390.c --- v2.4.3/linux/arch/s390x/kernel/sys_s390.c Mon Mar 19 12:35:11 2001 +++ linux/arch/s390x/kernel/sys_s390.c Wed Apr 11 19:02:29 2001 @@ -123,7 +123,7 @@ * * This is really horribly ugly. */ -asmlinkage int sys_ipc (uint call, int first, int second, +asmlinkage int sys_ipc (uint call, int first, long second, unsigned long third, void *ptr) { struct ipc_kludge tmp; diff -u --recursive --new-file v2.4.3/linux/arch/s390x/lib/Makefile linux/arch/s390x/lib/Makefile --- v2.4.3/linux/arch/s390x/lib/Makefile Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/lib/Makefile Wed Apr 11 19:02:29 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/s390x/lib/delay.c linux/arch/s390x/lib/delay.c --- v2.4.3/linux/arch/s390x/lib/delay.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/lib/delay.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * arch/s390/kernel/delay.c + * arch/s390x/kernel/delay.c * Precise Delay Loops for S390 * * S390 version diff -u --recursive --new-file v2.4.3/linux/arch/s390x/lib/misaligned.c linux/arch/s390x/lib/misaligned.c --- v2.4.3/linux/arch/s390x/lib/misaligned.c Wed Dec 31 16:00:00 1969 +++ linux/arch/s390x/lib/misaligned.c Wed Apr 11 19:02:30 2001 @@ -0,0 +1,34 @@ +/* + * 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_u64, __misaligned_u32 and __misaligned_u16. + */ + +#include <linux/module.h> +#include <linux/kernel.h> + +void __misaligned_u16(void) +{ + panic("misaligned (__u16 *) in __xchg\n"); +} + +void __misaligned_u32(void) +{ + panic("misaligned (__u32 *) in __xchg\n"); +} + +void __misaligned_u64(void) +{ + panic("misaligned (__u64 *) in __xchg\n"); +} + +EXPORT_SYMBOL(__misaligned_u16); +EXPORT_SYMBOL(__misaligned_u32); +EXPORT_SYMBOL(__misaligned_u64); diff -u --recursive --new-file v2.4.3/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c --- v2.4.3/linux/arch/s390x/mm/fault.c Mon Mar 19 12:35:11 2001 +++ linux/arch/s390x/mm/fault.c Wed Apr 11 19:02:30 2001 @@ -33,6 +33,34 @@ extern void die(const char *,struct pt_regs *,long); +extern spinlock_t timerlist_lock; + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + atomic_set(&global_irq_lock,0); +#endif + } else { + int loglevel_save = console_loglevel; + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate diff -u --recursive --new-file v2.4.3/linux/arch/s390x/mm/init.c linux/arch/s390x/mm/init.c --- v2.4.3/linux/arch/s390x/mm/init.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/mm/init.c Wed Apr 11 19:02:30 2001 @@ -35,31 +35,13 @@ #include <asm/pgalloc.h> #include <asm/dma.h> #include <asm/lowcore.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; -/* - * 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 an inode - * unused etc.. - * - * empty_bad_pte_table is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * empty_bad_pmd_table is the accompanying segment table: it is initialized - * to point to empty_bad_pte_table page tables. - * - * 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))); -pmd_t empty_bad_pmd_table[PTRS_PER_PMD] __attribute__((__aligned__(PAGE_SIZE))); -pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -88,79 +70,6 @@ return rc; } -static pmd_t *get_bad_pmd_table(void) -{ - pmd_t v; - int i; - - pmd_set(&v, empty_bad_pte_table); - - for (i = 0; i < PTRS_PER_PMD; i++) - empty_bad_pmd_table[i] = v; - - return empty_bad_pmd_table; -} - -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; -} - -pmd_t * -get_pmd_slow(pgd_t *pgd, unsigned long offset) -{ - pmd_t *pmd; - int i; - - pmd = (pmd_t *) __get_free_pages(GFP_KERNEL,2); - if (pgd_none(*pgd)) { - if (pmd) { - for (i = 0; i < PTRS_PER_PMD; i++) - pmd_clear(pmd+i); - pgd_set(pgd, pmd); - return pmd + offset; - } - pmd = (pmd_t *) get_bad_pmd_table(); - pgd_set(pgd, pmd); - return NULL; - } - free_pages((unsigned long)pmd,2); - if (pgd_bad(*pgd)) - BUG(); - return (pmd_t *) pgd_page(*pgd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - int i; - - pte = (pte_t*) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - for (i=0;i<PTRS_PER_PTE;i++) - pte_clear(pte+i); - pmd_set(pmd,pte); - return pte + offset; - } - pte = (pte_t*) get_bad_pte_table(); - pmd_set(pmd,pte); - return NULL; - } - free_page(__pa(pte)); - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -169,9 +78,9 @@ if(pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed += 4; if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed += 4; + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)), freed += 4; if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)), freed++; } while(pgtable_cache_size > low); } return freed; @@ -259,34 +168,34 @@ for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) { if (address >= end_mem) { - pgd_clear(pg_dir); - continue; + pgd_clear(pg_dir); + continue; } pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4); - pgd_set(pg_dir,pm_dir); + pgd_populate(&init_mm, pg_dir, pm_dir); for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) { - if (address >= end_mem) { - pmd_clear(pm_dir); - continue; - } - + if (address >= end_mem) { + pmd_clear(pm_dir); + continue; + } + pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - pmd_set(pm_dir,pt_dir); + pmd_populate(&init_mm, pm_dir, pt_dir); for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) { - pte = mk_pte_phys(address, PAGE_KERNEL); - if (address >= end_mem) { - pte_clear(&pte); - continue; - } - set_pte(pt_dir, pte); - address += PAGE_SIZE; + pte = mk_pte_phys(address, PAGE_KERNEL); + if (address >= end_mem) { + pte_clear(&pte); + continue; + } + set_pte(pt_dir, pte); + address += PAGE_SIZE; } } } - + /* enable virtual mapping in kernel mode */ __asm__ __volatile__("lctlg 1,1,%0\n\t" "lctlg 7,7,%0\n\t" diff -u --recursive --new-file v2.4.3/linux/arch/s390x/mm/ioremap.c linux/arch/s390x/mm/ioremap.c --- v2.4.3/linux/arch/s390x/mm/ioremap.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/mm/ioremap.c Wed Apr 11 19:02:30 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/s390x/tools/dasdfmt/dasdfmt.c linux/arch/s390x/tools/dasdfmt/dasdfmt.c --- v2.4.3/linux/arch/s390x/tools/dasdfmt/dasdfmt.c Fri Mar 2 11:12:06 2001 +++ linux/arch/s390x/tools/dasdfmt/dasdfmt.c Wed Apr 11 19:02:29 2001 @@ -7,6 +7,7 @@ * Author(s): Utz Bacher, <utz.bacher@de.ibm.com> * * Device-in-use-checks by Fritz Elfert, <felfert@to.com> + * Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com> * * 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 <label>] [-b <blocksize>] [<range>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \ "<diskspec>\n\n",prog_name); #else /* RANGE_FORMATTING */ - printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \ + printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \ "<diskspec>\n\n",prog_name); #endif /* RANGE_FORMATTING */ printf(" -t means testmode\n"); printf(" -v means verbose mode\n"); + printf(" -C means format compatible disk layout\n"); printf(" -V means print version\n"); printf(" -L means don't write disk label\n"); printf(" <label> is a label which is converted to EBCDIC and " \ @@ -200,7 +202,7 @@ /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -218,7 +220,8 @@ fclose(file); ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \ - "filesystem (are you sure to have the right param line?)\n", + "filesystem (are you sure to have the right parameter " \ + "dasd=xxx?)\n", prog_name); } @@ -488,14 +491,14 @@ } check_mounted(major_no, minor_no); + get_xno_from_xno(&devno,&major_no,&minor_no, + GIVEN_MAJOR|GIVEN_MINOR); if ((!writenolabel) && (!labelspec)) { sprintf(label,"LNX1 x%04x",devno); } if ( ((withoutprompt)&&(verbosity>=1)) || (!withoutprompt) ) { - get_xno_from_xno(&devno,&major_no,&minor_no, - GIVEN_MAJOR|GIVEN_MINOR); printf("\nI am going to format the device %s in the " \ "following way:\n",dev_name); printf(" Device number of device : 0x%x\n",devno); @@ -505,6 +508,9 @@ "no":"yes"); if (!writenolabel) printf(" Disk label : %s\n",label); + if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY) + printf(" Compatible Disk Layout : %s\n",(format_params.intensity&0x08)? + "yes":"no"); #ifdef RANGE_FORMATTING printf(" Start track : %d\n" \ ,format_params.start_unit); @@ -558,7 +564,7 @@ } - rc=ioctl(fd,BLKGETSIZE,&new_blksize); + rc=ioctl(fd,BLKSSZGET,&new_blksize); if (rc) { ERRMSG("%s: the ioctl call to get blocksize " \ "returned with the following error " \ @@ -664,9 +670,9 @@ opterr=0; #ifdef RANGE_FORMATTING - while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) { #endif /* RANGE_FORMATTING */ - while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) { + while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) { switch (oc) { case 'y': withoutprompt=1; @@ -686,6 +692,9 @@ case 'h': exit_usage(0); + case 'C': + format_params.intensity&=0x08; + break; case 'V': printf("%s version 0.99\n",prog_name); diff -u --recursive --new-file v2.4.3/linux/arch/s390x/tools/silo/silo.c linux/arch/s390x/tools/silo/silo.c --- v2.4.3/linux/arch/s390x/tools/silo/silo.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/tools/silo/silo.c Wed Apr 11 19:02:29 2001 @@ -9,6 +9,9 @@ * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com> * Fritz Elfert <felfert@to.com> contributed support for * /etc/silo.conf based on Intel's lilo + * Changes : + * 01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com> + * adapted to deal with devices and bootsects of various sizes */ #include <stddef.h> @@ -376,7 +379,7 @@ if ( errno == ENOENT ) { ITRY (creat ( o-> bootmap, O_RDWR )); } else { - PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap, + PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap, strerror(errno)); } } @@ -482,6 +485,7 @@ int bs, boots; char *tmpdev; char buffer[4096]={0,}; + int blocksize, sectsize; ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC)); ITRY (fstat (d_fd, &d_st)); ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC)); @@ -508,6 +512,7 @@ NTRY ( tmpdev = tmpnam(NULL) ); ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev)); ITRY (bd_fd = open (tmpdev, O_RDONLY)); + ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize)); ITRY (ioctl(s_fd,FIBMAP,&boots)); ITRY (ioctl (bd_fd, BIODASDRWTB, &boots)); PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots); @@ -515,13 +520,21 @@ close(s_fd); ITRY (unlink(tmpdev)); /* Now patch the bootsector */ + ITRY (stat (o->bootsect, &b_st)); + if ((sectsize = b_st.st_size) > blocksize ) + { + ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize); + rc = -1; + errno = EINVAL; + } ITRY (b_fd = open (o->bootsect, O_RDONLY)); - NTRY (read (b_fd, buffer, 4096)); + ITRY (read (b_fd, buffer, sectsize)); memset (buffer + 0xe0, 0, 8); *(int *) (buffer + 0xe0) = boots; if ( o -> testlevel <= 0 ) { - NTRY (write (d_fd, buffer, 4096)); - NTRY (write (d_fd, buffer, 4096)); + ITRY (write (d_fd, buffer, sectsize)); + ITRY (lseek (d_fd, blocksize, SEEK_SET)); + ITRY (write (d_fd, buffer, sectsize)); } close (b_fd); close (d_fd); diff -u --recursive --new-file v2.4.3/linux/arch/s390x/vmlinux.lds linux/arch/s390x/vmlinux.lds --- v2.4.3/linux/arch/s390x/vmlinux.lds Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/vmlinux.lds Wed Apr 11 19:02:29 2001 @@ -26,6 +26,10 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + _etext = .; /* End of text section */ .data : { /* Data */ diff -u --recursive --new-file v2.4.3/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.4.3/linux/arch/sh/config.in Thu Jan 4 13:19:13 2001 +++ linux/arch/sh/config.in Tue Apr 17 17:19:25 2001 @@ -7,6 +7,8 @@ define_bool CONFIG_SUPERH y 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' diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile --- v2.4.3/linux/arch/sh/kernel/Makefile Thu Jan 4 13:19:13 2001 +++ linux/arch/sh/kernel/Makefile Wed Apr 11 21:24:52 2001 @@ -20,16 +20,23 @@ obj-$(CONFIG_CF_ENABLER) += cf-enabler.o obj-$(CONFIG_CPU_SH4) += fpu.o -obj-$(CONFIG_PCI) += pci-sh.o obj-$(CONFIG_SH_RTC) += rtc.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o +ifeq ($(CONFIG_PCI),y) +obj-y += pci-sh.o +obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o +endif + obj-$(CONFIG_SH_HP600) += mach_hp600.o machine-specific-objs += mach_hp600.o obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o machine-specific-objs += mach_se.o setup_se.o io_se.o led_se.o +obj-$(CONFIG_SH_CAT68701) += mach_cat68701.o io_cat68701.o +machine-specific-objs += mach_cat68701.o io_cat68701.o + obj-$(CONFIG_SH_CQREEK) += setup_cqreek.o machine-specific-objs += setup_cqreek.o @@ -39,9 +46,13 @@ obj-$(CONFIG_HD64461) += setup_hd64461.o io_hd64461.o machine-specific-objs += setup_hd64461.o io_hd64461.o +obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) +=irq_intc2.o + # Doesn't compile well, so don't include in machine-specific-objs -obj-$(CONFIG_HD64465) += setup_hd64465.o io_hd64465.o -obj-$(CONFIG_SH_FOOBAR) += mach_foobar.o +obj-$(CONFIG_HD64465) += setup_hd64465.o io_hd64465.o hd64465_gpio.o +obj-$(CONFIG_SH_DMIDA) += mach_dmida.o +obj-$(CONFIG_SH_EC3104) += setup_ec3104.o io_ec3104.o mach_ec3104.o +obj-$(CONFIG_SH_DREAMCAST) += mach_dc.o setup_dc.o io_dc.o ifeq ($(CONFIG_SH_GENERIC),y) obj-y += $(machine-specific-objs) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/cf-enabler.c linux/arch/sh/kernel/cf-enabler.c --- v2.4.3/linux/arch/sh/kernel/cf-enabler.c Thu Aug 10 13:03:25 2000 +++ linux/arch/sh/kernel/cf-enabler.c Wed Apr 11 21:24:52 2001 @@ -8,13 +8,41 @@ * Enable the CF configuration. */ +#include <linux/config.h> #include <linux/init.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/hitachi_se.h> +#define CF_CIS_BASE 0xb8000000 +/* + * You can connect Compact Flash directly to the bus of SuperH. + * This is the enabler for that. + * + * SIM: How generic is this really? It looks pretty board, or at + * least SH sub-type, specific to me. + * I know it doesn't work on the Overdrive! + */ + +/* + * 0xB8000000 : Attribute + * 0xB8001000 : Common Memory + * 0xBA000000 : I/O + */ +static int __init cf_init_default(void) +{ +#ifdef CONFIG_IDE + /* Enable the card, and set the level interrupt */ + ctrl_outw(0x0042, CF_CIS_BASE+0x0200); +#endif + make_imask_irq(14); + disable_irq(14); + return 0; +} + +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_SOLUTION_ENGINE) +#include <asm/hitachi_se.h> /* * SolutionEngine @@ -70,37 +98,14 @@ ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200); return 0; } - -#define CF_CIS_BASE 0xb8000000 -/* - * You can connect Compact Flash directly to the bus of SuperH. - * This is the enabler for that. - * - * SIM: How generic is this really? It looks pretty board, or at - * least SH sub-type, specific to me. - * I know it doesn't work on the Overdrive! - */ - -/* - * 0xB8000000 : Attribute - * 0xB8001000 : Common Memory - * 0xBA000000 : I/O - */ - -static int __init cf_init_default(void) -{ - /* Enable the card, and set the level interrupt */ - ctrl_outw(0x0042, CF_CIS_BASE+0x0200); - make_imask_irq(14); - disable_irq(14); - return 0; -} +#endif int __init cf_init(void) { - if (MACH_SE) { +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_SOLUTION_ENGINE) + if (MACH_SE) return cf_init_se(); - } +#endif return cf_init_default(); } diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.4.3/linux/arch/sh/kernel/entry.S Sun Jan 28 18:56:00 2001 +++ linux/arch/sh/kernel/entry.S Wed Apr 11 21:24:52 2001 @@ -182,7 +182,7 @@ jsr @r0 mov r15, r4 ! - tst #0xff, r0 + tst r0, r0 bf/s 0f lds r10, pr rts @@ -550,10 +550,10 @@ ret_with_reschedule: stc k_current, r1 mov.l @(need_resched,r1), r0 - tst #0xff, r0 + tst r0, r0 bf reschedule mov.l @(sigpending,r1), r0 - tst #0xff, r0 + tst r0, r0 bt restore_all signal_return: mov r15, r4 diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/hd64465_gpio.c linux/arch/sh/kernel/hd64465_gpio.c --- v2.4.3/linux/arch/sh/kernel/hd64465_gpio.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/hd64465_gpio.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,185 @@ +/* + * $Id: hd64465_gpio.c,v 1.1 2001/01/02 15:35:22 mjd Exp $ + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc + * + * GPIO pin support for HD64465 companion chip. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/hd64465_gpio.h> + +#define _PORTOF(portpin) (((portpin)>>3)&0x7) +#define _PINOF(portpin) ((portpin)&0x7) + +/* Register addresses parametrised on port */ +#define GPIO_CR(port) (HD64465_REG_GPACR+((port)<<1)) +#define GPIO_DR(port) (HD64465_REG_GPADR+((port)<<1)) +#define GPIO_ICR(port) (HD64465_REG_GPAICR+((port)<<1)) +#define GPIO_ISR(port) (HD64465_REG_GPAISR+((port)<<1)) + +#define GPIO_NPORTS 5 + +#define MODNAME "hd64465_gpio" + +EXPORT_SYMBOL(hd64465_gpio_configure); +EXPORT_SYMBOL(hd64465_gpio_get_pin); +EXPORT_SYMBOL(hd64465_gpio_get_port); +EXPORT_SYMBOL(hd64465_gpio_register_irq); +EXPORT_SYMBOL(hd64465_gpio_set_pin); +EXPORT_SYMBOL(hd64465_gpio_set_port); +EXPORT_SYMBOL(hd64465_gpio_unregister_irq); + +/* TODO: each port should be protected with a spinlock */ + + +void hd64465_gpio_configure(int portpin, int direction) +{ + unsigned short cr; + unsigned int shift = (_PINOF(portpin)<<1); + + cr = inw(GPIO_CR(_PORTOF(portpin))); + cr &= ~(3<<shift); + cr |= direction<<shift; + outw(cr, GPIO_CR(_PORTOF(portpin))); +} + +void hd64465_gpio_set_pin(int portpin, unsigned int value) +{ + unsigned short d; + unsigned short mask = 1<<(_PINOF(portpin)); + + d = inw(GPIO_DR(_PORTOF(portpin))); + if (value) + d |= mask; + else + d &= ~mask; + outw(d, GPIO_DR(_PORTOF(portpin))); +} + +unsigned int hd64465_gpio_get_pin(int portpin) +{ + return inw(GPIO_DR(_PORTOF(portpin))) & (1<<(_PINOF(portpin))); +} + +/* TODO: for cleaner atomicity semantics, add a mask to this routine */ + +void hd64465_gpio_set_port(int port, unsigned int value) +{ + outw(value, GPIO_DR(port)); +} + +unsigned int hd64465_gpio_get_port(int port) +{ + return inw(GPIO_DR(port)); +} + + +static struct { + void (*func)(int portpin, void *dev); + void *dev; +} handlers[GPIO_NPORTS * 8]; + +static void hd64465_gpio_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + unsigned short port, pin, isr, mask, portpin; + + for (port=0 ; port<GPIO_NPORTS ; port++) { + isr = inw(GPIO_ISR(port)); + + for (pin=0 ; pin<8 ; pin++) { + mask = 1<<pin; + if (isr & mask) { + portpin = (port<<3)|pin; + if (handlers[portpin].func != 0) + handlers[portpin].func(portpin, handlers[portpin].dev); + else + printk(KERN_NOTICE "unexpected GPIO interrupt, pin %c%d\n", + port+'A', (int)pin); + } + } + + /* Write 1s back to ISR to clear it? That's what the manual says.. */ + outw(isr, GPIO_ISR(port)); + } +} + +void hd64465_gpio_register_irq(int portpin, int mode, + void (*handler)(int portpin, void *dev), void *dev) +{ + unsigned long flags; + unsigned short icr, mask; + + if (handler == 0) + return; + + save_and_cli(flags); + + handlers[portpin].func = handler; + handlers[portpin].dev = dev; + + /* + * Configure Interrupt Control Register + */ + icr = inw(GPIO_ICR(_PORTOF(portpin))); + mask = (1<<_PINOF(portpin)); + + /* unmask interrupt */ + icr &= ~mask; + + /* set TS bit */ + mask <<= 8; + icr &= ~mask; + if (mode == HD64465_GPIO_RISING) + icr |= mask; + + outw(icr, GPIO_ICR(_PORTOF(portpin))); + + restore_flags(flags); +} + +void hd64465_gpio_unregister_irq(int portpin) +{ + unsigned long flags; + unsigned short icr; + + save_and_cli(flags); + + /* + * Configure Interrupt Control Register + */ + icr = inw(GPIO_ICR(_PORTOF(portpin))); + icr |= (1<<_PINOF(portpin)); /* mask interrupt */ + outw(icr, GPIO_ICR(_PORTOF(portpin))); + + handlers[portpin].func = 0; + handlers[portpin].dev = 0; + + restore_flags(flags); +} + +static int __init hd64465_gpio_init(void) +{ + /* TODO: check return values */ + request_region(HD64465_REG_GPACR, 0x1000, MODNAME); + request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt, + SA_INTERRUPT, MODNAME, 0); + + printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO); + return 0; +} + +static void __exit hd64465_gpio_exit(void) +{ + release_region(HD64465_REG_GPACR, 0x1000); + free_irq(HD64465_IRQ_GPIO, 0); +} + +module_init(hd64465_gpio_init); +module_exit(hd64465_gpio_exit); diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io.c linux/arch/sh/kernel/io.c --- v2.4.3/linux/arch/sh/kernel/io.c Mon Oct 2 11:57:34 2000 +++ linux/arch/sh/kernel/io.c Wed Apr 11 21:24:52 2001 @@ -8,123 +8,149 @@ */ #include <asm/io.h> +#include <linux/module.h> -unsigned int _inb(unsigned long port) +unsigned char _inb(unsigned long port) { return __inb(port); } +EXPORT_SYMBOL(_inb); -unsigned int _inw(unsigned long port) +unsigned short _inw(unsigned long port) { return __inw(port); } +EXPORT_SYMBOL(_inw); unsigned int _inl(unsigned long port) { return __inl(port); } +EXPORT_SYMBOL(_inl); void _outb(unsigned char b, unsigned long port) { __outb(b, port); } +EXPORT_SYMBOL(_outb); void _outw(unsigned short b, unsigned long port) { __outw(b, port); } +EXPORT_SYMBOL(_outw); + void _outl(unsigned int b, unsigned long port) { __outl(b, port); } +EXPORT_SYMBOL(_outl); + -unsigned int _inb_p(unsigned long port) +unsigned char _inb_p(unsigned long port) { return __inb_p(port); } +EXPORT_SYMBOL(_inb_p); -unsigned int _inw_p(unsigned long port) +unsigned short _inw_p(unsigned long port) { return __inw_p(port); } +EXPORT_SYMBOL(_inw_p); + void _outb_p(unsigned char b, unsigned long port) { __outb_p(b, port); } +EXPORT_SYMBOL(_outb_p); void _outw_p(unsigned short b, unsigned long port) { __outw_p(b, port); } +EXPORT_SYMBOL(_outw_p); void _insb(unsigned long port, void *buffer, unsigned long count) { return __insb(port, buffer, count); } +EXPORT_SYMBOL(_insb); void _insw(unsigned long port, void *buffer, unsigned long count) { __insw(port, buffer, count); } +EXPORT_SYMBOL(_insw); void _insl(unsigned long port, void *buffer, unsigned long count) { __insl(port, buffer, count); } +EXPORT_SYMBOL(_insl); void _outsb(unsigned long port, const void *buffer, unsigned long count) { __outsb(port, buffer, count); } +EXPORT_SYMBOL(_outsb); void _outsw(unsigned long port, const void *buffer, unsigned long count) { __outsw(port, buffer, count); } +EXPORT_SYMBOL(_outsw); void _outsl(unsigned long port, const void *buffer, unsigned long count) { __outsl(port, buffer, count); } +EXPORT_SYMBOL(_outsl); -unsigned long ___raw_readb(unsigned long addr) +unsigned char ___raw_readb(unsigned long addr) { return __readb(addr); } +EXPORT_SYMBOL(___raw_readb); -unsigned long ___raw_readw(unsigned long addr) +unsigned short ___raw_readw(unsigned long addr) { return __readw(addr); } +EXPORT_SYMBOL(___raw_readw); -unsigned long ___raw_readl(unsigned long addr) +unsigned int ___raw_readl(unsigned long addr) { return __readl(addr); } +EXPORT_SYMBOL(___raw_readl); -unsigned long _readb(unsigned long addr) +unsigned char _readb(unsigned long addr) { unsigned long r = __readb(addr); mb(); return r; } +EXPORT_SYMBOL(_readb); -unsigned long _readw(unsigned long addr) +unsigned short _readw(unsigned long addr) { unsigned long r = __readw(addr); mb(); return r; } +EXPORT_SYMBOL(_readw); -unsigned long _readl(unsigned long addr) +unsigned int _readl(unsigned long addr) { unsigned long r = __readl(addr); mb(); return r; } +EXPORT_SYMBOL(_readl); void ___raw_writeb(unsigned char b, unsigned long addr) { @@ -135,29 +161,34 @@ { __writew(b, addr); } +EXPORT_SYMBOL(___raw_writew); void ___raw_writel(unsigned int b, unsigned long addr) { __writel(b, addr); } +EXPORT_SYMBOL(___raw_writel); void _writeb(unsigned char b, unsigned long addr) { __writeb(b, addr); mb(); } +EXPORT_SYMBOL(_writeb); void _writew(unsigned short b, unsigned long addr) { __writew(b, addr); mb(); } +EXPORT_SYMBOL(_writew); void _writel(unsigned int b, unsigned long addr) { __writel(b, addr); mb(); } +EXPORT_SYMBOL(_writel); /* * Copy data from IO memory space to "real" memory space. diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_cat68701.c linux/arch/sh/kernel/io_cat68701.c --- v2.4.3/linux/arch/sh/kernel/io_cat68701.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/io_cat68701.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,248 @@ +/* + * linux/arch/sh/kernel/io_cat68701.c + * + * Copyright (C) 2000 Niibe Yutaka + * 2001 Yutaro Ebihara + * + * I/O routine and setup routines for A-ONE Corp CAT-68701 SH7708 Board + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include <asm/io.h> +#include <asm/machvec.h> +#include <linux/module.h> + +#define SH3_PCMCIA_BUG_WORKAROUND 1 +#define DUMMY_READ_AREA6 0xba000000 + +#define PORT2ADDR(x) (cat68701_isa_port2addr(x)) + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); +} + +unsigned char cat68701_inb(unsigned long port) +{ + return *(volatile unsigned char*)PORT2ADDR(port); +} + +unsigned short cat68701_inw(unsigned long port) +{ + return *(volatile unsigned short*)PORT2ADDR(port); +} + +unsigned int cat68701_inl(unsigned long port) +{ + return *(volatile unsigned long*)PORT2ADDR(port); +} + +unsigned char cat68701_inb_p(unsigned long port) +{ + unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); + + delay(); + return v; +} + +unsigned short cat68701_inw_p(unsigned long port) +{ + unsigned long v = *(volatile unsigned short*)PORT2ADDR(port); + + delay(); + return v; +} + +unsigned int cat68701_inl_p(unsigned long port) +{ + unsigned long v = *(volatile unsigned long*)PORT2ADDR(port); + + delay(); + return v; +} + +void cat68701_insb(unsigned long port, void *buffer, unsigned long count) +{ + unsigned char *buf=buffer; + while(count--) *buf++=inb(port); +} + +void cat68701_insw(unsigned long port, void *buffer, unsigned long count) +{ + unsigned short *buf=buffer; + while(count--) *buf++=inw(port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +void cat68701_insl(unsigned long port, void *buffer, unsigned long count) +{ + unsigned long *buf=buffer; + while(count--) *buf++=inl(port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +void cat68701_outb(unsigned char b, unsigned long port) +{ + *(volatile unsigned char*)PORT2ADDR(port) = b; +} + +void cat68701_outw(unsigned short b, unsigned long port) +{ + *(volatile unsigned short*)PORT2ADDR(port) = b; +} + +void cat68701_outl(unsigned int b, unsigned long port) +{ + *(volatile unsigned long*)PORT2ADDR(port) = b; +} + +void cat68701_outb_p(unsigned char b, unsigned long port) +{ + *(volatile unsigned char*)PORT2ADDR(port) = b; + delay(); +} + +void cat68701_outw_p(unsigned short b, unsigned long port) +{ + *(volatile unsigned short*)PORT2ADDR(port) = b; + delay(); +} + +void cat68701_outl_p(unsigned int b, unsigned long port) +{ + *(volatile unsigned long*)PORT2ADDR(port) = b; + delay(); +} + +void cat68701_outsb(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned char *buf=buffer; + while(count--) outb(*buf++, port); +} + +void cat68701_outsw(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned short *buf=buffer; + while(count--) outw(*buf++, port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +void cat68701_outsl(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned long *buf=buffer; + while(count--) outl(*buf++, port); +#ifdef SH3_PCMCIA_BUG_WORKAROUND + ctrl_inb (DUMMY_READ_AREA6); +#endif +} + +unsigned char cat68701_readb(unsigned long addr) +{ + return *(volatile unsigned char*)addr; +} + +unsigned short cat68701_readw(unsigned long addr) +{ + return *(volatile unsigned short*)addr; +} + +unsigned int cat68701_readl(unsigned long addr) +{ + return *(volatile unsigned long*)addr; +} + +void cat68701_writeb(unsigned char b, unsigned long addr) +{ + *(volatile unsigned char*)addr = b; +} + +void cat68701_writew(unsigned short b, unsigned long addr) +{ + *(volatile unsigned short*)addr = b; +} + +void cat68701_writel(unsigned int b, unsigned long addr) +{ + *(volatile unsigned long*)addr = b; +} + +void * cat68701_ioremap(unsigned long offset, unsigned long size) +{ + return (void *) P2SEGADDR(offset); +} +EXPORT_SYMBOL(cat68701_ioremap); + +void cat68701_iounmap(void *addr) +{ +} +EXPORT_SYMBOL(cat68701_iounmap); + +unsigned long cat68701_isa_port2addr(unsigned long offset) +{ + /* CompactFlash (IDE) */ + if(((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6)) + return 0xba000000 + offset; + + /* INPUT PORT */ + if((offset >= 0x3fc) && (offset <= 0x3fd)) + return 0xb4007000 + offset; + + /* OUTPUT PORT */ + if((offset >= 0x3fe) && (offset <= 0x3ff)) + return 0xb4007400 + offset; + + return offset + 0xb4000000; /* other I/O (EREA 5)*/ +} + + +int cat68701_irq_demux(int irq) +{ + if(irq==13) return 14; + if(irq==7) return 10; + return irq; +} + + + +/*-------------------------------------------------------*/ + +void setup_cat68701(){ + /* dummy read erea5 (CS8900A) */ +} + +void init_cat68701_IRQ(){ + make_imask_irq(10); + make_imask_irq(14); +} + +#ifdef CONFIG_HEARTBEAT +#include <linux/sched.h> +void heartbeat_cat68701() +{ + static unsigned int cnt = 0, period = 0 , bit = 0; + cnt += 1; + if (cnt < period) { + return; + } + cnt = 0; + + /* Go through the points (roughly!): + * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 + */ + period = 110 - ( (300<<FSHIFT)/ + ((avenrun[0]/5) + (3<<FSHIFT)) ); + + if(bit){ bit=0; }else{ bit=1; } + outw(bit<<15,0x3fe); +} +#endif /* CONFIG_HEARTBEAT */ diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_dc.c linux/arch/sh/kernel/io_dc.c --- v2.4.3/linux/arch/sh/kernel/io_dc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/io_dc.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,13 @@ +/* + * $Id: io_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $ + * I/O routines for SEGA Dreamcast + */ + +#include <linux/config.h> +#include <asm/io.h> +#include <asm/machvec.h> + +unsigned long dreamcast_isa_port2addr(unsigned long offset) +{ + return offset + 0xa0000000; +} diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_ec3104.c linux/arch/sh/kernel/io_ec3104.c --- v2.4.3/linux/arch/sh/kernel/io_ec3104.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/io_ec3104.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,83 @@ +/* + * linux/arch/sh/kernel/io_ec3104.c + * EC3104 companion chip support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/ec3104.h> + +/* + * EC3104 has a real ISA bus which we redirect low port accesses to (the + * actual device on mine is a ESS 1868, and I don't want to hack the driver + * more than strictly necessary). I am not going to duplicate the + * hard coding of PC addresses (for the 16550s aso) here though; it's just + * too ugly. + */ + +#define low_port(port) ((port) < 0x10000) + +static inline unsigned long port2addr(unsigned long port) +{ + switch(port >> 16) { + case 0: + return EC3104_ISA_BASE + port * 2; + + /* XXX hack. it's unclear what to do about the serial ports */ + case 1: + return EC3104_BASE + (port&0xffff) * 4; + + default: + /* XXX PCMCIA */ + return 0; + } +} + +unsigned char ec3104_inb(unsigned long port) +{ + u8 ret; + + ret = *(volatile u8 *)port2addr(port); + + return ret; +} + +unsigned short ec3104_inw(unsigned long port) +{ + BUG(); +} + +unsigned long ec3104_inl(unsigned long port) +{ + BUG(); +} + +void ec3104_outb(unsigned char data, unsigned long port) +{ + *(volatile u8 *)port2addr(port) = data; +} + +void ec3104_outw(unsigned short data, unsigned long port) +{ + BUG(); +} + +void ec3104_outl(unsigned long data, unsigned long port) +{ + BUG(); +} diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_generic.c linux/arch/sh/kernel/io_generic.c --- v2.4.3/linux/arch/sh/kernel/io_generic.c Thu Aug 10 13:03:25 2000 +++ linux/arch/sh/kernel/io_generic.c Wed Apr 11 21:24:52 2001 @@ -15,6 +15,7 @@ #include <asm/io.h> #include <asm/machvec.h> +#include <linux/module.h> #if defined(__sh3__) /* I'm not sure SH7709 has this kind of bug */ @@ -31,22 +32,22 @@ ctrl_inw(0xa0000000); } -unsigned long generic_inb(unsigned int port) +unsigned char generic_inb(unsigned long port) { return *(volatile unsigned char*)PORT2ADDR(port); } -unsigned long generic_inw(unsigned int port) +unsigned short generic_inw(unsigned long port) { return *(volatile unsigned short*)PORT2ADDR(port); } -unsigned long generic_inl(unsigned int port) +unsigned int generic_inl(unsigned long port) { return *(volatile unsigned long*)PORT2ADDR(port); } -unsigned long generic_inb_p(unsigned int port) +unsigned char generic_inb_p(unsigned long port) { unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); @@ -54,7 +55,7 @@ return v; } -unsigned long generic_inw_p(unsigned int port) +unsigned short generic_inw_p(unsigned long port) { unsigned long v = *(volatile unsigned short*)PORT2ADDR(port); @@ -62,7 +63,7 @@ return v; } -unsigned long generic_inl_p(unsigned int port) +unsigned int generic_inl_p(unsigned long port) { unsigned long v = *(volatile unsigned long*)PORT2ADDR(port); @@ -70,13 +71,13 @@ return v; } -void generic_insb(unsigned int port, void *buffer, unsigned long count) +void generic_insb(unsigned long port, void *buffer, unsigned long count) { unsigned char *buf=buffer; while(count--) *buf++=inb(port); } -void generic_insw(unsigned int port, void *buffer, unsigned long count) +void generic_insw(unsigned long port, void *buffer, unsigned long count) { unsigned short *buf=buffer; while(count--) *buf++=inw(port); @@ -85,7 +86,7 @@ #endif } -void generic_insl(unsigned int port, void *buffer, unsigned long count) +void generic_insl(unsigned long port, void *buffer, unsigned long count) { unsigned long *buf=buffer; while(count--) *buf++=inl(port); @@ -94,46 +95,46 @@ #endif } -void generic_outb(unsigned long b, unsigned int port) +void generic_outb(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; } -void generic_outw(unsigned long b, unsigned int port) +void generic_outw(unsigned short b, unsigned long port) { *(volatile unsigned short*)PORT2ADDR(port) = b; } -void generic_outl(unsigned long b, unsigned int port) +void generic_outl(unsigned int b, unsigned long port) { *(volatile unsigned long*)PORT2ADDR(port) = b; } -void generic_outb_p(unsigned long b, unsigned int port) +void generic_outb_p(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; delay(); } -void generic_outw_p(unsigned long b, unsigned int port) +void generic_outw_p(unsigned short b, unsigned long port) { *(volatile unsigned short*)PORT2ADDR(port) = b; delay(); } -void generic_outl_p(unsigned long b, unsigned int port) +void generic_outl_p(unsigned int b, unsigned long port) { *(volatile unsigned long*)PORT2ADDR(port) = b; delay(); } -void generic_outsb(unsigned int port, const void *buffer, unsigned long count) +void generic_outsb(unsigned long port, const void *buffer, unsigned long count) { const unsigned char *buf=buffer; while(count--) outb(*buf++, port); } -void generic_outsw(unsigned int port, const void *buffer, unsigned long count) +void generic_outsw(unsigned long port, const void *buffer, unsigned long count) { const unsigned short *buf=buffer; while(count--) outw(*buf++, port); @@ -142,7 +143,7 @@ #endif } -void generic_outsl(unsigned int port, const void *buffer, unsigned long count) +void generic_outsl(unsigned long port, const void *buffer, unsigned long count) { const unsigned long *buf=buffer; while(count--) outl(*buf++, port); @@ -151,17 +152,17 @@ #endif } -unsigned long generic_readb(unsigned long addr) +unsigned char generic_readb(unsigned long addr) { return *(volatile unsigned char*)addr; } -unsigned long generic_readw(unsigned long addr) +unsigned short generic_readw(unsigned long addr) { return *(volatile unsigned short*)addr; } -unsigned long generic_readl(unsigned long addr) +unsigned int generic_readl(unsigned long addr) { return *(volatile unsigned long*)addr; } @@ -185,15 +186,12 @@ { return (void *) P2SEGADDR(offset); } - -void * generic_ioremap_nocache (unsigned long offset, unsigned long size) -{ - return (void *) P2SEGADDR(offset); -} +EXPORT_SYMBOL(generic_ioremap); void generic_iounmap(void *addr) { } +EXPORT_SYMBOL(generic_iounmap); unsigned long generic_isa_port2addr(unsigned long offset) { diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_hd64461.c linux/arch/sh/kernel/io_hd64461.c --- v2.4.3/linux/arch/sh/kernel/io_hd64461.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/io_hd64461.c Wed Apr 11 21:24:52 2001 @@ -27,6 +27,12 @@ detail of CF's memory mapped addressing. */ if (0x1f0<=port && port<=0x1f7) return 0xb5000000 + port; if (port == 0x3f6) return 0xb50001fe; + if (port == 0x3f7) return 0xb50001ff; + + /* ide1 */ + if (0x170<=port && port<=0x177) return 0xba000000 + port; + if (port == 0x376) return 0xba000376; + if (port == 0x377) return 0xba000377; #endif /* ??? */ @@ -50,80 +56,80 @@ ctrl_inw(0xa0000000); } -unsigned long hd64461_inb(unsigned int port) +unsigned char hd64461_inb(unsigned long port) { return *(volatile unsigned char*)PORT2ADDR(port); } -unsigned long hd64461_inb_p(unsigned int port) +unsigned char hd64461_inb_p(unsigned long port) { unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); delay(); return v; } -unsigned long hd64461_inw(unsigned int port) +unsigned short hd64461_inw(unsigned long port) { return *(volatile unsigned short*)PORT2ADDR(port); } -unsigned long hd64461_inl(unsigned int port) +unsigned int hd64461_inl(unsigned long port) { return *(volatile unsigned long*)PORT2ADDR(port); } -void hd64461_insb(unsigned int port, void *buffer, unsigned long count) +void hd64461_insb(unsigned long port, void *buffer, unsigned long count) { unsigned char *buf=buffer; while(count--) *buf++=inb(port); } -void hd64461_insw(unsigned int port, void *buffer, unsigned long count) +void hd64461_insw(unsigned long port, void *buffer, unsigned long count) { unsigned short *buf=buffer; while(count--) *buf++=inw(port); } -void hd64461_insl(unsigned int port, void *buffer, unsigned long count) +void hd64461_insl(unsigned long port, void *buffer, unsigned long count) { unsigned long *buf=buffer; while(count--) *buf++=inl(port); } -void hd64461_outb(unsigned long b, unsigned int port) +void hd64461_outb(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; } -void hd64461_outb_p(unsigned long b, unsigned int port) +void hd64461_outb_p(unsigned char b, unsigned long port) { *(volatile unsigned char*)PORT2ADDR(port) = b; delay(); } -void hd64461_outw(unsigned long b, unsigned int port) +void hd64461_outw(unsigned short b, unsigned long port) { *(volatile unsigned short*)PORT2ADDR(port) = b; } -void hd64461_outl(unsigned long b, unsigned int port) +void hd64461_outl(unsigned int b, unsigned long port) { *(volatile unsigned long*)PORT2ADDR(port) = b; } -void hd64461_outsb(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count) { const unsigned char *buf=buffer; while(count--) outb(*buf++, port); } -void hd64461_outsw(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count) { const unsigned short *buf=buffer; while(count--) outw(*buf++, port); } -void hd64461_outsl(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count) { const unsigned long *buf=buffer; while(count--) outl(*buf++, port); diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_hd64465.c linux/arch/sh/kernel/io_hd64465.c --- v2.4.3/linux/arch/sh/kernel/io_hd64465.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/io_hd64465.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,249 @@ +/* + * $Id: io_hd64465.c,v 1.6 2001/02/15 09:13:51 dave_mckay Exp $ + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc + * + * Derived from io_hd64461.c, which bore the message: + * Copyright (C) 2000 YAEGASHI Takeshi + * + * Typical I/O routines for HD64465 system. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/io.h> +#include <asm/hd64465.h> + + +#define HD64465_DEBUG 0 + +#if HD64465_DEBUG +#define DPRINTK(args...) printk(args) +#define DIPRINTK(n, args...) if (hd64465_io_debug>(n)) printk(args) +#else +#define DPRINTK(args...) +#define DIPRINTK(n, args...) +#endif + + + +/* This is a hack suitable only for debugging IO port problems */ +int hd64465_io_debug; +EXPORT_SYMBOL(hd64465_io_debug); + +/* Low iomap maps port 0-1K to addresses in 8byte chunks */ +#define HD64465_IOMAP_LO_THRESH 0x400 +#define HD64465_IOMAP_LO_SHIFT 3 +#define HD64465_IOMAP_LO_MASK ((1<<HD64465_IOMAP_LO_SHIFT)-1) +#define HD64465_IOMAP_LO_NMAP (HD64465_IOMAP_LO_THRESH>>HD64465_IOMAP_LO_SHIFT) +static unsigned long hd64465_iomap_lo[HD64465_IOMAP_LO_NMAP]; +static unsigned char hd64465_iomap_lo_shift[HD64465_IOMAP_LO_NMAP]; + +/* High iomap maps port 1K-64K to addresses in 1K chunks */ +#define HD64465_IOMAP_HI_THRESH 0x10000 +#define HD64465_IOMAP_HI_SHIFT 10 +#define HD64465_IOMAP_HI_MASK ((1<<HD64465_IOMAP_HI_SHIFT)-1) +#define HD64465_IOMAP_HI_NMAP (HD64465_IOMAP_HI_THRESH>>HD64465_IOMAP_HI_SHIFT) +static unsigned long hd64465_iomap_hi[HD64465_IOMAP_HI_NMAP]; +static unsigned char hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP]; + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +void hd64465_port_map(unsigned short baseport, unsigned int nports, + unsigned long addr, unsigned char shift) +{ + unsigned int port, endport = baseport + nports; + + DPRINTK("hd64465_port_map(base=0x%04hx, n=0x%04hx, addr=0x%08lx,endport=0x%04x)\n", + baseport, nports, addr,endport); + + for (port = baseport ; + port < endport && port < HD64465_IOMAP_LO_THRESH ; + port += (1<<HD64465_IOMAP_LO_SHIFT)) { + DPRINTK(" maplo[0x%x] = 0x%08lx\n", port, addr); + hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = addr; + hd64465_iomap_lo_shift[port>>HD64465_IOMAP_LO_SHIFT] = shift; + addr += (1<<(HD64465_IOMAP_LO_SHIFT)); + } + + for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; + port < endport && port < HD64465_IOMAP_HI_THRESH ; + port += (1<<HD64465_IOMAP_HI_SHIFT)) { + DPRINTK(" maphi[0x%x] = 0x%08lx\n", port, addr); + hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = addr; + hd64465_iomap_hi_shift[port>>HD64465_IOMAP_HI_SHIFT] = shift; + addr += (1<<(HD64465_IOMAP_HI_SHIFT)); + } +} +EXPORT_SYMBOL(hd64465_port_map); + +void hd64465_port_unmap(unsigned short baseport, unsigned int nports) +{ + unsigned int port, endport = baseport + nports; + + DPRINTK("hd64465_port_unmap(base=0x%04hx, n=0x%04hx)\n", + baseport, nports); + + for (port = baseport ; + port < endport && port < HD64465_IOMAP_LO_THRESH ; + port += (1<<HD64465_IOMAP_LO_SHIFT)) { + hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = 0; + } + + for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; + port < endport && port < HD64465_IOMAP_HI_THRESH ; + port += (1<<HD64465_IOMAP_HI_SHIFT)) { + hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = 0; + } +} +EXPORT_SYMBOL(hd64465_port_unmap); + +static /*__inline__*/ unsigned long PORT2ADDR(unsigned long port) +{ + unsigned long addr = 0; + unsigned char shift; + + /* handle remapping of low IO ports */ + if (port < HD64465_IOMAP_LO_THRESH) { + addr = hd64465_iomap_lo[port >> HD64465_IOMAP_LO_SHIFT]; + shift = hd64465_iomap_lo_shift[port >> HD64465_IOMAP_LO_SHIFT]; + if (addr != 0) + addr += (port & HD64465_IOMAP_LO_MASK) << shift; + else + printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); + } else if (port < HD64465_IOMAP_HI_THRESH) { + addr = hd64465_iomap_hi[port >> HD64465_IOMAP_HI_SHIFT]; + shift = hd64465_iomap_hi_shift[port >> HD64465_IOMAP_HI_SHIFT]; + if (addr != 0) + addr += (port & HD64465_IOMAP_HI_MASK) << shift; + else + printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); + } + + /* HD64465 internal devices (0xb0000000) */ + else if (port < 0x20000) + addr = CONFIG_HD64465_IOBASE + port - 0x10000; + + /* Whole physical address space (0xa0000000) */ + else + addr = P2SEGADDR(port); + + DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr); + + return addr; +} + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); +} + +unsigned char hd64465_inb(unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr); + + DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b); + return b; +} + +unsigned char hd64465_inb_p(unsigned long port) +{ + unsigned long v; + unsigned long addr = PORT2ADDR(port); + + v = (addr == 0 ? 0 : *(volatile unsigned char*)addr); + delay(); + DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v); + return v; +} + +unsigned short hd64465_inw(unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr); + DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b); + return b; +} + +unsigned int hd64465_inl(unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr); + DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b); + return b; +} + +void hd64465_insb(unsigned long port, void *buffer, unsigned long count) +{ + unsigned char *buf=buffer; + while(count--) *buf++=inb(port); +} + +void hd64465_insw(unsigned long port, void *buffer, unsigned long count) +{ + unsigned short *buf=buffer; + while(count--) *buf++=inw(port); +} + +void hd64465_insl(unsigned long port, void *buffer, unsigned long count) +{ + unsigned long *buf=buffer; + while(count--) *buf++=inl(port); +} + +void hd64465_outb(unsigned char b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + + DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr); + if (addr != 0) + *(volatile unsigned char*)addr = b; +} + +void hd64465_outb_p(unsigned char b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + + DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr); + if (addr != 0) + *(volatile unsigned char*)addr = b; + delay(); +} + +void hd64465_outw(unsigned short b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr); + if (addr != 0) + *(volatile unsigned short*)addr = b; +} + +void hd64465_outl(unsigned int b, unsigned long port) +{ + unsigned long addr = PORT2ADDR(port); + DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr); + if (addr != 0) + *(volatile unsigned long*)addr = b; +} + +void hd64465_outsb(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned char *buf=buffer; + while(count--) outb(*buf++, port); +} + +void hd64465_outsw(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned short *buf=buffer; + while(count--) outw(*buf++, port); +} + +void hd64465_outsl(unsigned long port, const void *buffer, unsigned long count) +{ + const unsigned long *buf=buffer; + while(count--) outl(*buf++, port); +} diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_se.c linux/arch/sh/kernel/io_se.c --- v2.4.3/linux/arch/sh/kernel/io_se.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/io_se.c Wed Apr 11 21:24:52 2001 @@ -43,7 +43,7 @@ } static inline int -shifted_port(unsigned int port) +shifted_port(unsigned long port) { /* For IDE registers, value is not shifted */ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) @@ -53,10 +53,10 @@ } #define maybebadio(name,port) \ - printk("bad PC-like io %s for port 0x%x at 0x%08x\n", \ + printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ #name, (port), (__u32) __builtin_return_address(0)) -unsigned long se_inb(unsigned int port) +unsigned char se_inb(unsigned long port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); @@ -66,7 +66,7 @@ return (*port2adr(port))&0xff; } -unsigned long se_inb_p(unsigned int port) +unsigned char se_inb_p(unsigned long port) { unsigned long v; @@ -80,7 +80,7 @@ return v; } -unsigned long se_inw(unsigned int port) +unsigned short se_inw(unsigned long port) { if (port >= 0x2000 || (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) @@ -90,13 +90,13 @@ return 0; } -unsigned long se_inl(unsigned int port) +unsigned int se_inl(unsigned long port) { maybebadio(inl, port); return 0; } -void se_outb(unsigned long value, unsigned int port) +void se_outb(unsigned char value, unsigned long port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) *(__u8 *)(sh_pcic_io_wbase + port) = value; @@ -106,7 +106,7 @@ *(port2adr(port)) = value; } -void se_outb_p(unsigned long value, unsigned int port) +void se_outb_p(unsigned char value, unsigned long port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) *(__u8 *)(sh_pcic_io_wbase + port) = value; @@ -117,7 +117,7 @@ delay(); } -void se_outw(unsigned long value, unsigned int port) +void se_outw(unsigned short value, unsigned long port) { if (port >= 0x2000 || (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) @@ -126,12 +126,12 @@ maybebadio(outw, port); } -void se_outl(unsigned long value, unsigned int port) +void se_outl(unsigned int value, unsigned long port) { maybebadio(outl, port); } -void se_insb(unsigned int port, void *addr, unsigned long count) +void se_insb(unsigned long port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -148,19 +148,19 @@ } } -void se_insw(unsigned int port, void *addr, unsigned long count) +void se_insw(unsigned long port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); while (count--) *((__u16 *) addr)++ = *p; } -void se_insl(unsigned int port, void *addr, unsigned long count) +void se_insl(unsigned long port, void *addr, unsigned long count) { maybebadio(insl, port); } -void se_outsb(unsigned int port, const void *addr, unsigned long count) +void se_outsb(unsigned long port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -177,29 +177,29 @@ } } -void se_outsw(unsigned int port, const void *addr, unsigned long count) +void se_outsw(unsigned long port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); while (count--) *p = *((__u16 *) addr)++; } -void se_outsl(unsigned int port, const void *addr, unsigned long count) +void se_outsl(unsigned long port, const void *addr, unsigned long count) { maybebadio(outsw, port); } -unsigned long se_readb(unsigned long addr) +unsigned char se_readb(unsigned long addr) { return *(volatile unsigned char*)addr; } -unsigned long se_readw(unsigned long addr) +unsigned short se_readw(unsigned long addr) { return *(volatile unsigned short*)addr; } -unsigned long se_readl(unsigned long addr) +unsigned int se_readl(unsigned long addr) { return *(volatile unsigned long*)addr; } diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/io_unknown.c linux/arch/sh/kernel/io_unknown.c --- v2.4.3/linux/arch/sh/kernel/io_unknown.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/io_unknown.c Wed Apr 11 21:24:52 2001 @@ -43,5 +43,4 @@ UNKNOWN_ALIAS(writel) UNKNOWN_ALIAS(isa_port2addr) UNKNOWN_ALIAS(ioremap) -UNKNOWN_ALIAS(ioremap_nocache) UNKNOWN_ALIAS(iounmap) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/irq_intc2.c linux/arch/sh/kernel/irq_intc2.c --- v2.4.3/linux/arch/sh/kernel/irq_intc2.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/irq_intc2.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,127 @@ +/* + * linux/arch/sh/kernel/irq_intc2.c + * + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Interrupt handling for INTC2-based IRQ. + * + * These are the "new Hitachi style" interrupts, as present on the + * Hitachi 7751 and the STM ST40 STB1. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/machvec.h> + + +struct intc2_data { + unsigned int addr; /* Address of Interrupt Priority Register */ + int mask; /*Mask to apply */ +}; + + +static struct intc2_data intc2_data[NR_INTC2_IRQS]; + +static void enable_intc2_irq(unsigned int irq); +static void disable_intc2_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_intc2_irq disable_intc2_irq + +static void mask_and_ack_intc2(unsigned int); +static void end_intc2_irq(unsigned int irq); + +static unsigned int startup_intc2_irq(unsigned int irq) +{ + enable_intc2_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type intc2_irq_type = { + "INTC2-based-IRQ", + startup_intc2_irq, + shutdown_intc2_irq, + enable_intc2_irq, + disable_intc2_irq, + mask_and_ack_intc2, + end_intc2_irq +}; + +static void disable_intc2_irq(unsigned int irq) +{ + unsigned addr; + int offset=irq-INTC2_FIRST_IRQ; + unsigned val,flags; + + // Sanity check + if(offset<0 || offset>=NR_INTC2_IRQS) return; + + addr=intc2_data[offset].addr+INTC2_INTMSK_OFFSET; + + save_and_cli(flags); + val=ctrl_inl(addr); + val|=intc2_data[offset].mask; + ctrl_outl(val,addr); + + restore_flags(flags); +} + +static void enable_intc2_irq(unsigned int irq) +{ + int offset=irq-INTC2_FIRST_IRQ; + + // Sanity check + if(offset<0 || offset>=NR_INTC2_IRQS) return; + + ctrl_outl(intc2_data[offset].mask, + intc2_data[offset].addr+INTC2_INTMSKCLR_OFFSET); + +} + +static void mask_and_ack_intc2(unsigned int irq) +{ + disable_intc2_irq(irq); +} + +static void end_intc2_irq(unsigned int irq) +{ + enable_intc2_irq(irq); +} + +void make_intc2_irq(unsigned int irq, unsigned int addr, + unsigned int group,int pos, int priority) +{ + int offset=irq-INTC2_FIRST_IRQ; + unsigned flags,val; + + if(offset<0 || offset>=NR_INTC2_IRQS) { + return; + } + + disable_irq_nosync(irq); + /* Fill the the data we need */ + intc2_data[offset].addr=addr; + intc2_data[offset].mask=1<<pos; + + /* Set the priority level */ + save_and_cli(flags); + val=ctrl_inl(addr+INTC2_INTPRI_OFFSET); + val|=(priority)<< (group<<4); + ctrl_outl(val,addr+INTC2_INTPRI_OFFSET); + restore_flags(flags); + + irq_desc[irq].handler=&intc2_irq_type; + + disable_intc2_irq(irq); +} + + + diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/irq_ipr.c linux/arch/sh/kernel/irq_ipr.c --- v2.4.3/linux/arch/sh/kernel/irq_ipr.c Mon Oct 2 11:57:34 2000 +++ linux/arch/sh/kernel/irq_ipr.c Wed Apr 11 21:24:52 2001 @@ -116,14 +116,96 @@ disable_ipr_irq(irq); } +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static unsigned char pint_map[256]; +static unsigned long portcr_mask = 0; + +static void enable_pint_irq(unsigned int irq); +static void disable_pint_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_pint_irq disable_pint_irq + +static void mask_and_ack_pint(unsigned int); +static void end_pint_irq(unsigned int irq); + +static unsigned int startup_pint_irq(unsigned int irq) +{ + enable_pint_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type pint_irq_type = { + "PINT-IRQ", + startup_pint_irq, + shutdown_pint_irq, + enable_pint_irq, + disable_pint_irq, + mask_and_ack_pint, + end_pint_irq +}; + +static void disable_pint_irq(unsigned int irq) +{ + unsigned long val, flags; + + save_and_cli(flags); + val = ctrl_inw(INTC_INTER); + val &= ~(1 << (irq - PINT_IRQ_BASE)); + ctrl_outw(val, INTC_INTER); /* disable PINTn */ + portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2); + restore_flags(flags); +} + +static void enable_pint_irq(unsigned int irq) +{ + unsigned long val, flags; + + save_and_cli(flags); + val = ctrl_inw(INTC_INTER); + val |= 1 << (irq - PINT_IRQ_BASE); + ctrl_outw(val, INTC_INTER); /* enable PINTn */ + portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2; + restore_flags(flags); +} + +static void mask_and_ack_pint(unsigned int irq) +{ + disable_pint_irq(irq); +} + +static void end_pint_irq(unsigned int irq) +{ + enable_pint_irq(irq); +} + +void make_pint_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &pint_irq_type; + disable_pint_irq(irq); +} +#endif + void __init init_IRQ(void) { + int i; + make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); +#ifdef SCI_ERI_IRQ make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); +#endif + +#ifdef SCIF1_ERI_IRQ + make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); + make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); + make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); + make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); +#endif #ifdef SCIF_ERI_IRQ make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); @@ -171,12 +253,30 @@ * You should set corresponding bits of PFC to "00" * to enable these interrupts. */ - make_ipr_irq(IRQ0_IRQ, IRQ0_IRP_ADDR, IRQ0_IRP_POS, IRQ0_PRIORITY); - make_ipr_irq(IRQ1_IRQ, IRQ1_IRP_ADDR, IRQ1_IRP_POS, IRQ1_PRIORITY); - make_ipr_irq(IRQ2_IRQ, IRQ2_IRP_ADDR, IRQ2_IRP_POS, IRQ2_PRIORITY); - make_ipr_irq(IRQ3_IRQ, IRQ3_IRP_ADDR, IRQ3_IRP_POS, IRQ3_PRIORITY); - make_ipr_irq(IRQ4_IRQ, IRQ4_IRP_ADDR, IRQ4_IRP_POS, IRQ4_PRIORITY); - make_ipr_irq(IRQ5_IRQ, IRQ5_IRP_ADDR, IRQ5_IRP_POS, IRQ5_PRIORITY); + make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY); + make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY); + make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY); + make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY); + make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY); + make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY); + make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY); + make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY); + enable_ipr_irq(PINT0_IRQ); + enable_ipr_irq(PINT8_IRQ); + + for(i = 0; i < 16; i++) + make_pint_irq(PINT_IRQ_BASE + i); + for(i = 0; i < 256; i++) + { + if(i & 1) pint_map[i] = 0; + else if(i & 2) pint_map[i] = 1; + else if(i & 4) pint_map[i] = 2; + else if(i & 8) pint_map[i] = 3; + else if(i & 0x10) pint_map[i] = 4; + else if(i & 0x20) pint_map[i] = 5; + else if(i & 0x40) pint_map[i] = 6; + else if(i & 0x80) pint_map[i] = 7; + } #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */ /* Perform the machine specific initialisation */ @@ -184,3 +284,43 @@ sh_mv.mv_init_irq(); } } +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +int ipr_irq_demux(int irq) +{ + unsigned long creg, dreg, d, sav; + + if(irq == PINT0_IRQ) + { +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + creg = PORT_PACR; + dreg = PORT_PADR; +#else + creg = PORT_PCCR; + dreg = PORT_PCDR; +#endif + sav = ctrl_inw(creg); + ctrl_outw(sav | portcr_mask, creg); + d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & ctrl_inw(INTC_INTER) & 0xff; + ctrl_outw(sav, creg); + if(d == 0) return irq; + return PINT_IRQ_BASE + pint_map[d]; + } + else if(irq == PINT8_IRQ) + { +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + creg = PORT_PBCR; + dreg = PORT_PBDR; +#else + creg = PORT_PFCR; + dreg = PORT_PFDR; +#endif + sav = ctrl_inw(creg); + ctrl_outw(sav | (portcr_mask >> 16), creg); + d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & (ctrl_inw(INTC_INTER) >> 8) & 0xff; + ctrl_outw(sav, creg); + if(d == 0) return irq; + return PINT_IRQ_BASE + 8 + pint_map[d]; + } + return irq; +} +#endif diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_cat68701.c linux/arch/sh/kernel/mach_cat68701.c --- v2.4.3/linux/arch/sh/kernel/mach_cat68701.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/mach_cat68701.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,72 @@ +/* + * linux/arch/sh/kernel/mach_cat68701.c + * + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * 2001 Yutaro Ebihara (ebihara@si-linux.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine vector for the A-ONE corp. CAT-68701 SH7708 board + */ + +#include <linux/config.h> +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> +#include <asm/io_cat68701.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_cat68701 __initmv = { + mv_name: "CAT-68701", + mv_nr_irqs: 32, + mv_inb: cat68701_inb, + mv_inw: cat68701_inw, + mv_inl: cat68701_inl, + mv_outb: cat68701_outb, + mv_outw: cat68701_outw, + mv_outl: cat68701_outl, + + mv_inb_p: cat68701_inb_p, + mv_inw_p: cat68701_inw, + mv_inl_p: cat68701_inl, + mv_outb_p: cat68701_outb_p, + mv_outw_p: cat68701_outw, + mv_outl_p: cat68701_outl, + + mv_insb: cat68701_insb, + mv_insw: cat68701_insw, + mv_insl: cat68701_insl, + mv_outsb: cat68701_outsb, + mv_outsw: cat68701_outsw, + mv_outsl: cat68701_outsl, + + mv_readb: cat68701_readb, + mv_readw: cat68701_readw, + mv_readl: cat68701_readl, + mv_writeb: cat68701_writeb, + mv_writew: cat68701_writew, + mv_writel: cat68701_writel, + + mv_ioremap: cat68701_ioremap, + mv_iounmap: cat68701_iounmap, + + mv_isa_port2addr: cat68701_isa_port2addr, + mv_irq_demux: cat68701_irq_demux, + + mv_init_arch: setup_cat68701, + mv_init_irq: init_cat68701_IRQ, +#ifdef CONFIG_HEARTBEAT + mv_heartbeat: heartbeat_cat68701, +#endif + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + +}; +ALIAS_MV(cat68701) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_dc.c linux/arch/sh/kernel/mach_dc.c --- v2.4.3/linux/arch/sh/kernel/mach_dc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/mach_dc.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,66 @@ +/* + * $Id: mach_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $ + * SEGA Dreamcast machine vector + */ + +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/machvec_init.h> + +#include <asm/io_generic.h> +#include <asm/io_dc.h> +#include <asm/irq.h> + +void __init setup_dreamcast(void); +void __init dreamcast_pcibios_init(void); + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_dreamcast __initmv = { + mv_name: "dreamcast", + + mv_nr_irqs: 48, + + mv_inb: generic_inb, + mv_inw: generic_inw, + mv_inl: generic_inl, + mv_outb: generic_outb, + mv_outw: generic_outw, + mv_outl: generic_outl, + + mv_inb_p: generic_inb_p, + mv_inw_p: generic_inw, + mv_inl_p: generic_inl, + mv_outb_p: generic_outb_p, + mv_outw_p: generic_outw, + mv_outl_p: generic_outl, + + mv_insb: generic_insb, + mv_insw: generic_insw, + mv_insl: generic_insl, + mv_outsb: generic_outsb, + mv_outsw: generic_outsw, + mv_outsl: generic_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_ioremap: generic_ioremap, + mv_iounmap: generic_iounmap, + + mv_init_arch: setup_dreamcast, +#ifdef CONFIG_PCI + mv_init_pci: dreamcast_pcibios_init, +#endif + mv_isa_port2addr: dreamcast_isa_port2addr, + + mv_hw_dreamcast: 1, +}; +ALIAS_MV(dreamcast) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_dmida.c linux/arch/sh/kernel/mach_dmida.c --- v2.4.3/linux/arch/sh/kernel/mach_dmida.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/mach_dmida.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,73 @@ +/* + * linux/arch/sh/kernel/mach_dmida.c + * + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc + * + * Derived from mach_hp600.c, which bore the message: + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine vector for the DataMyte Industrial Digital Assistant(tm). + * See http://www.dmida.com + * + */ + +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> + +#include <asm/io.h> +#include <asm/hd64465.h> +#include <asm/irq.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_dmida __initmv = { + mv_name: "DMIDA", + + mv_nr_irqs: HD64465_IRQ_BASE+HD64465_IRQ_NUM, + + mv_inb: hd64465_inb, + mv_inw: hd64465_inw, + mv_inl: hd64465_inl, + mv_outb: hd64465_outb, + mv_outw: hd64465_outw, + mv_outl: hd64465_outl, + + mv_inb_p: hd64465_inb_p, + mv_inw_p: hd64465_inw, + mv_inl_p: hd64465_inl, + mv_outb_p: hd64465_outb_p, + mv_outw_p: hd64465_outw, + mv_outl_p: hd64465_outl, + + mv_insb: hd64465_insb, + mv_insw: hd64465_insw, + mv_insl: hd64465_insl, + mv_outsb: hd64465_outsb, + mv_outsw: hd64465_outsw, + mv_outsl: hd64465_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64465_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + + mv_hw_hd64465: 1, +}; +ALIAS_MV(dmida) + diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_ec3104.c linux/arch/sh/kernel/mach_ec3104.c --- v2.4.3/linux/arch/sh/kernel/mach_ec3104.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/mach_ec3104.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,69 @@ +/* + * linux/arch/sh/kernel/mach_ec3104.c + * EC3104 companion chip support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + +#include <linux/init.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> + +#include <asm/io.h> +#include <asm/irq.h> + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_ec3104 __initmv = { + mv_name: "EC3104", + + mv_nr_irqs: 96, + + mv_inb: ec3104_inb, + mv_inw: ec3104_inw, + mv_inl: ec3104_inl, + mv_outb: ec3104_outb, + mv_outw: ec3104_outw, + mv_outl: ec3104_outl, + + mv_inb_p: generic_inb_p, + mv_inw_p: generic_inw, + mv_inl_p: generic_inl, + mv_outb_p: generic_outb_p, + mv_outw_p: generic_outw, + mv_outl_p: generic_outl, + + mv_insb: generic_insb, + mv_insw: generic_insw, + mv_insl: generic_insl, + mv_outsb: generic_outsb, + mv_outsw: generic_outsw, + mv_outsl: generic_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: ec3104_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, +}; + +ALIAS_MV(ec3104) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_hp600.c linux/arch/sh/kernel/mach_hp600.c --- v2.4.3/linux/arch/sh/kernel/mach_hp600.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/mach_hp600.c Wed Apr 11 21:24:52 2001 @@ -12,6 +12,7 @@ #include <linux/init.h> #include <asm/machvec.h> +#include <asm/rtc.h> #include <asm/machvec_init.h> #include <asm/io_hd64461.h> @@ -22,8 +23,8 @@ * The Machine Vector */ -struct sh_machine_vector mv_hp600 __initmv = { - mv_name: "HP600", +struct sh_machine_vector mv_hp620 __initmv = { + mv_name: "hp620", mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ @@ -57,7 +58,101 @@ mv_irq_demux: hd64461_irq_demux, + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + + mv_hw_hp600: 1, + mv_hw_hp620: 1, + mv_hw_hd64461: 1, +}; +ALIAS_MV(hp620) + + +struct sh_machine_vector mv_hp680 __initmv = { + mv_name: "hp680", + + mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ + + mv_inb: hd64461_inb, + mv_inw: hd64461_inw, + mv_inl: hd64461_inl, + mv_outb: hd64461_outb, + mv_outw: hd64461_outw, + mv_outl: hd64461_outl, + + mv_inb_p: hd64461_inb_p, + mv_inw_p: hd64461_inw, + mv_inl_p: hd64461_inl, + mv_outb_p: hd64461_outb_p, + mv_outw_p: hd64461_outw, + mv_outl_p: hd64461_outl, + + mv_insb: hd64461_insb, + mv_insw: hd64461_insw, + mv_insl: hd64461_insl, + mv_outsb: hd64461_outsb, + mv_outsw: hd64461_outsw, + mv_outsl: hd64461_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64461_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + + mv_hw_hp600: 1, + mv_hw_hp680: 1, + mv_hw_hd64461: 1, +}; +ALIAS_MV(hp680) + + +struct sh_machine_vector mv_hp690 __initmv = { + mv_name: "hp690", + + mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ + + mv_inb: hd64461_inb, + mv_inw: hd64461_inw, + mv_inl: hd64461_inl, + mv_outb: hd64461_outb, + mv_outw: hd64461_outw, + mv_outl: hd64461_outl, + + mv_inb_p: hd64461_inb_p, + mv_inw_p: hd64461_inw, + mv_inl_p: hd64461_inl, + mv_outb_p: hd64461_outb_p, + mv_outw_p: hd64461_outw, + mv_outl_p: hd64461_outl, + + mv_insb: hd64461_insb, + mv_insw: hd64461_insw, + mv_insl: hd64461_insl, + mv_outsb: hd64461_outsb, + mv_outsw: hd64461_outsw, + mv_outsl: hd64461_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64461_irq_demux, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, + mv_hw_hp600: 1, + mv_hw_hp690: 1, mv_hw_hd64461: 1, }; -ALIAS_MV(hp600) +ALIAS_MV(hp690) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_se.c linux/arch/sh/kernel/mach_se.c --- v2.4.3/linux/arch/sh/kernel/mach_se.c Thu Aug 10 13:03:25 2000 +++ linux/arch/sh/kernel/mach_se.c Wed Apr 11 21:24:52 2001 @@ -13,6 +13,7 @@ #include <linux/init.h> #include <asm/machvec.h> +#include <asm/rtc.h> #include <asm/machvec_init.h> #include <asm/io_se.h> @@ -65,7 +66,6 @@ mv_writel: se_writel, mv_ioremap: generic_ioremap, - mv_ioremap_nocache: generic_ioremap_nocache, mv_iounmap: generic_iounmap, mv_isa_port2addr: se_isa_port2addr, @@ -75,6 +75,9 @@ #ifdef CONFIG_HEARTBEAT mv_heartbeat: heartbeat_se, #endif + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, mv_hw_se: 1, }; diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/mach_unknown.c linux/arch/sh/kernel/mach_unknown.c --- v2.4.3/linux/arch/sh/kernel/mach_unknown.c Thu Aug 10 13:03:25 2000 +++ linux/arch/sh/kernel/mach_unknown.c Wed Apr 11 21:24:52 2001 @@ -17,6 +17,7 @@ #include <asm/io_unknown.h> +#include <asm/rtc.h> /* * The Machine Vector */ @@ -61,9 +62,11 @@ mv_writel: unknown_writel, mv_ioremap: unknown_ioremap, - mv_ioremap_nocache: unknown_ioremap_nocache, mv_iounmap: unknown_iounmap, mv_isa_port2addr: unknown_isa_port2addr, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, }; ALIAS_MV(unknown) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/pci_st40.c linux/arch/sh/kernel/pci_st40.c --- v2.4.3/linux/arch/sh/kernel/pci_st40.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/pci_st40.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Support functions for the ST40 PCI hardware. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <asm/pci.h> +#include <linux/irq.h> + +#include "pci_st40.h" + +/* This is in P2 of course */ +#define ST40PCI_BASE_ADDRESS (0xb0000000) +#define ST40PCI_MEM_ADDRESS (ST40PCI_BASE_ADDRESS+0x0) +#define ST40PCI_IO_ADDRESS (ST40PCI_BASE_ADDRESS+0x06000000) +#define ST40PCI_REG_ADDRESS (ST40PCI_BASE_ADDRESS+0x07000000) + +#define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x)) + +#define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg)) +#define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg)) +#define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg)) + +#define ST40PCI_READ(reg) readl(ST40PCI_REG(reg)) +#define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg)) +#define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg)) + +#define ST40PCI_SERR_IRQ 64 +#define ST40PCI_SERR_INT_GROUP 0 +#define ST40PCI_SERR_INT_POS 0 +#define ST40PCI_SERR_INT_PRI 15 + +#define ST40PCI_ERR_IRQ 65 +#define ST40PCI_ERR_INT_GROUP 1 +#define ST40PCI_ERR_INT_POS 1 +#define ST40PCI_ERR_INT_PRI 14 + + +/* Macros to extract PLL params */ +#define PLL_MDIV(reg) ( ((unsigned)reg) & 0xff ) +#define PLL_NDIV(reg) ( (((unsigned)reg)>>8) & 0xff ) +#define PLL_PDIV(reg) ( (((unsigned)reg)>>16) & 0x3 ) +#define PLL_SETUP(reg) ( (((unsigned)reg)>>19) & 0x1ff ) + +/* Build up the appropriate settings */ +#define PLL_SET(mdiv,ndiv,pdiv,setup) \ +( ((mdiv)&0xff) | (((ndiv)&0xff)<<8) | (((pdiv)&3)<<16)| (((setup)&0x1ff)<<19)) + +#define PLLPCICR (0xbb040000+0x10) + +#define PLLPCICR_POWERON (1<<28) +#define PLLPCICR_OUT_EN (1<<29) +#define PLLPCICR_LOCKSELECT (1<<30) +#define PLLPCICR_LOCK (1<<31) + + +#define PLL_25MHZ 0x793c8512 +#define PLL_33MHZ PLL_SET(18,88,3,295) + + +static __init void SetPCIPLL(void) +{ + /* Stop the PLL */ + writel(0, PLLPCICR); + + /* Always run at 33Mhz. The PCI clock is totally async + * to the rest of the system + */ + writel(PLL_33MHZ | PLLPCICR_POWERON, PLLPCICR); + + printk("ST40PCI: Waiting for PCI PLL to lock\n"); + while ((readl(PLLPCICR) & PLLPCICR_LOCK) == 0); + writel(readl(PLLPCICR) | PLLPCICR_OUT_EN, PLLPCICR); +} + + +static void st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs) +{ + + unsigned pci_int, pci_air, pci_cir, pci_aint; + + pci_int = ST40PCI_READ(INT); + pci_cir = ST40PCI_READ(CIR); + pci_air = ST40PCI_READ(AIR); + + if (pci_int) { + printk("PCI INTERRUPT!\n"); + printk("PCI INT -> 0x%x\n", pci_int & 0xffff); + printk("PCI AIR -> 0x%x\n", pci_air); + printk("PCI CIR -> 0x%x\n", pci_cir); + ST40PCI_WRITE(INT, ~0); + } + + pci_aint = ST40PCI_READ(AINT); + if (pci_aint) { + printk("PCI ARB INTERRUPT!\n"); + printk("PCI AINT -> 0x%x\n", pci_aint); + printk("PCI AIR -> 0x%x\n", pci_air); + printk("PCI CIR -> 0x%x\n", pci_cir); + ST40PCI_WRITE(AINT, ~0); + } + +} + + +/* Rounds a number UP to the nearest power of two. Used for + * sizing the PCI window. + */ +static u32 __init r2p2(u32 num) +{ + int i = 31; + u32 tmp = num; + + if (num == 0) + return 0; + + do { + if (tmp & (1 << 31)) + break; + i--; + tmp <<= 1; + } while (i >= 0); + + tmp = 1 << i; + /* If the original number isn't a power of 2, round it up */ + if (tmp != num) + tmp <<= 1; + + return tmp; +} + + +int __init st40pci_init(unsigned memStart, unsigned memSize) +{ + u32 lsr0; + + SetPCIPLL(); + + /* Initialises the ST40 pci subsystem, performing a reset, then programming + * up the address space decoders appropriately + */ + + /* Should reset core here as well methink */ + + ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_SOFT_RESET); + + /* Loop while core resets */ + while (ST40PCI_READ(CR) & CR_SOFT_RESET); + + /* Now, lets reset all the cards on the bus with extreme prejudice */ + ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL); + udelay(250); + + /* Set bus active, take it out of reset */ + ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_CFINT | CR_PFCS | CR_PFE); + + /* The PCI spec says that no access must be made to the bus until 1 second + * after reset. This seem ludicrously long, but some delay is needed here + */ + mdelay(1000); + + /* Switch off interrupts */ + ST40PCI_WRITE(INTM, 0); + ST40PCI_WRITE(AINT, 0); + + /* Allow it to be a master */ + + ST40PCI_WRITE_SHORT(CSR_CMD, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_IO); + + /* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000 + * on the PCI bus. This allows a nice 1-1 bus to phys mapping. + */ + + + ST40PCI_WRITE(MBR, 0x10000000); + /* Always set the max size 128M (actually, it is only 96MB wide) */ + ST40PCI_WRITE(MBMR, 0x07ff0000); + + /* I/O addresses are mapped at 0xb6000000 -> 0xb7000000. These are changed to 0, to + * allow cards that have legacy io such as vga to function correctly. This gives a + * maximum of 64K of io/space as only the bottom 16 bits of the address are copied + * over to the bus when the transaction is made. 64K of io space is more than enough + */ + ST40PCI_WRITE(IOBR, 0x0); + /* Set up the 64K window */ + ST40PCI_WRITE(IOBMR, 0x0); + + /* Now we set up the mbars so the PCI bus can see the memory of the machine */ + + if (memSize < (64 * 1024)) { + printk("Ridiculous memory size of 0x%x?\n",memSize); + return 0; + } + + lsr0 = + (memSize > + (512 * 1024 * 1024)) ? 0x1fff0001 : ((r2p2(memSize) - + 0x10000) | 0x1); + + ST40PCI_WRITE(LSR0, lsr0); + + ST40PCI_WRITE(CSR_MBAR0, memStart); + ST40PCI_WRITE(LAR0, memStart); + + /* Maximise timeout values */ + ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff); + ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff); + ST40PCI_WRITE_BYTE(CSR_MIT, 0xff); + + + /* Install the pci interrupt handlers */ + make_intc2_irq(ST40PCI_SERR_IRQ, INTC2_BASE0, + ST40PCI_SERR_INT_GROUP, ST40PCI_SERR_INT_POS, + ST40PCI_SERR_INT_PRI); + + make_intc2_irq(ST40PCI_ERR_IRQ, INTC2_BASE0, ST40PCI_ERR_INT_GROUP, + ST40PCI_ERR_INT_POS, ST40PCI_ERR_INT_PRI); + + + return 1; +} + + +#define SET_CONFIG_BITS(bus,devfn,where)\ + (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0)) + +#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where) + + +static int CheckForMasterAbort(void) +{ + if (ST40PCI_READ(INT) & INT_MADIM) { + /* Should we clear config space version as well ??? */ + ST40PCI_WRITE(INT, INT_MADIM); + ST40PCI_WRITE_SHORT(CSR_STATUS, 0); + return 1; + } + + return 0; +} + +/* Write to config register */ +static int st40pci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + *val = ST40PCI_READ_BYTE(PDR + (where & 3)); + + if (CheckForMasterAbort()) + *val = 0xff; + + + return PCIBIOS_SUCCESSFUL; +} + +static int st40pci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + *val = ST40PCI_READ_SHORT(PDR + (where & 2)); + + if (CheckForMasterAbort()) + *val = 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + + +static int st40pci_read_config_dword(struct pci_dev *dev, int where, + u32 * val) +{ + + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + *val = ST40PCI_READ(PDR); + + if (CheckForMasterAbort()) + *val = 0xffffffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int st40pci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + ST40PCI_WRITE_BYTE(PDR + (where & 3), val); + + CheckForMasterAbort(); + + return PCIBIOS_SUCCESSFUL; +} + + +static int st40pci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + ST40PCI_WRITE_SHORT(PDR + (where & 2), val); + + CheckForMasterAbort(); + + return PCIBIOS_SUCCESSFUL; +} + +static int st40pci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where)); + + ST40PCI_WRITE(PDR, val); + + CheckForMasterAbort(); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_config_ops = { + st40pci_read_config_byte, + st40pci_read_config_word, + st40pci_read_config_dword, + st40pci_write_config_byte, + st40pci_write_config_word, + st40pci_write_config_dword +}; + + +/* Everything hangs off this */ +static struct pci_bus *pci_root_bus; + + +static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) +{ + return PCI_SLOT(dev->devfn); +} + + +/* This needs to be shunted out of here into the board specific bit */ +#define HARP_PCI_IRQ 1 +#define HARP_BRIDGE_IRQ 2 +#define OVERDRIVE_SLOT0_IRQ 0 + +static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (slot) { +#ifdef CONFIG_SH_STB1_HARP + case 2: /*This is the PCI slot on the */ + return HARP_PCI_IRQ; + case 1: /* this is the bridge */ + return HARP_BRIDGE_IRQ; +#elif defined(CONFIG_SH_STB1_OVERDRIVE) + case 1: + case 2: + case 3: + return slot - 1; +#else +#error Unknown board +#endif + default: + return -1; + } +} + + +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; +} + +void __init st40_pcibios_init(void) +{ + extern unsigned long memory_start, memory_end; + + /* The pci subsytem needs to know where memory is and how much + * of it there is. I've simply made these globals. A better mechanism + * is probably needed. + */ + st40pci_init(PHYSADDR(memory_start), + PHYSADDR(memory_end) - PHYSADDR(memory_start)); + + if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq, + SA_INTERRUPT, "st40pci", NULL)) { + printk(KERN_ERR "st40pci: Cannot hook interrupt\n"); + return; + } + + /* Enable the PCI interrupts on the device */ + ST40PCI_WRITE(INTM, ~0); + ST40PCI_WRITE(AINT, ~0); + + /* Map the io address apprioately */ +#ifdef CONFIG_HD64465 + hd64465_port_map(PCIBIOS_MIN_IO, (64 * 1024) - PCIBIOS_MIN_IO + 1, + ST40_IO_ADDR + PCIBIOS_MIN_IO, 0); +#endif + + /* ok, do the scan man */ + pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); + pci_assign_unassigned_resources(); + pci_fixup_irqs(no_swizzle, map_harp_irq); + +} + +int 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 (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_fixup_bus(struct pci_bus *bus) +{ +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ +} + +void __init pcibios_update_resource(struct pci_dev *dev, + struct resource *root, + struct resource *res, int resource) +{ + + unsigned long where, size; + u32 reg; + + printk("PCI: Assigning %3s %08lx to %s\n", + res->flags & IORESOURCE_IO ? "IO" : "MEM", + res->start, dev->name); + + 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_update_irq(struct pci_dev *dev, int irq) +{ + printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/pci_st40.h linux/arch/sh/kernel/pci_st40.h --- v2.4.3/linux/arch/sh/kernel/pci_st40.h Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/pci_st40.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Defintions for the ST40 PCI hardware. + */ + +#ifndef __PCI_ST40_H__ +#define __PCI_ST40_H__ + +#define ST40PCI_VCR_STATUS 0x00 + +#define ST40PCI_VCR_VERSION 0x08 + +#define ST40PCI_CR 0x10 + +#define CR_SOFT_RESET (1<<12) +#define CR_PFCS (1<<11) +#define CR_PFE (1<<9) +#define CR_BMAM (1<<6) +#define CR_HOST (1<<5) +#define CR_CLKEN (1<<4) +#define CR_SOCS (1<<3) +#define CR_IOCS (1<<2) +#define CR_RSTCTL (1<<1) +#define CR_CFINT (1<<0) +#define CR_LOCK_MASK 0x5a000000 + + +#define ST40PCI_LSR0 0X14 +#define ST40PCI_LAR0 0x1c + +#define ST40PCI_INT 0x24 +#define INT_MADIM (1<<2) + + +#define ST40PCI_INTM 0x28 +#define ST40PCI_AIR 0x2c +#define ST40PCI_CIR 0x30 +#define ST40PCI_AINT 0x40 +#define ST40PCI_AINTM 0x44 +#define ST40PCI_BMIR 0x48 +#define ST40PCI_PAR 0x4c +#define ST40PCI_MBR 0x50 +#define ST40PCI_IOBR 0x54 +#define ST40PCI_PINT 0x58 +#define ST40PCI_PINTM 0x5c +#define ST40PCI_MBMR 0x70 +#define ST40PCI_IOBMR 0x74 +#define ST40PCI_PDR 0x78 + +/* These are configs space registers */ +#define ST40PCI_CSR_VID 0x10000 +#define ST40PCI_CSR_DID 0x10002 +#define ST40PCI_CSR_CMD 0x10004 +#define ST40PCI_CSR_STATUS 0x10006 +#define ST40PCI_CSR_MBAR0 0x10010 +#define ST40PCI_CSR_TRDY 0x10040 +#define ST40PCI_CSR_RETRY 0x10041 +#define ST40PCI_CSR_MIT 0x1000d + +#define ST40_IO_ADDR 0xb6000000 + +#endif /* __PCI_ST40_H__ */ diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.4.3/linux/arch/sh/kernel/process.c Fri Feb 9 11:29:44 2001 +++ linux/arch/sh/kernel/process.c Wed Apr 11 21:24:52 2001 @@ -139,10 +139,6 @@ /* * This is the mechanism for creating a new kernel thread. * - * NOTE! Only a kernel-only process(ie the swapper or direct descendants - * who haven't done an "execve()") should use this: it will work within - * a system call from a "real" process, but the process memory space will - * not be free'd until both the parent and the child have exited. */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ @@ -154,7 +150,7 @@ register unsigned long __sc9 __asm__ ("r9") = (long) fn; __asm__("trapa #0x12\n\t" /* Linux/SH system call */ - "tst #0xff, r0\n\t" /* child or parent? */ + "tst r0, r0\n\t" /* child or parent? */ "bf 1f\n\t" /* parent - jump */ "jsr @r9\n\t" /* call fn */ " mov r8, r4\n\t" /* push argument */ diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c --- v2.4.3/linux/arch/sh/kernel/ptrace.c Fri Dec 29 14:07:20 2000 +++ linux/arch/sh/kernel/ptrace.c Wed Apr 11 21:24:52 2001 @@ -175,14 +175,16 @@ if (request == PTRACE_ATTACH) { if (child == tsk) goto out_tsk; - if ((!child->dumpable || - (tsk->uid != child->euid) || + if(((tsk->uid != child->euid) || (tsk->uid != child->suid) || (tsk->uid != child->uid) || (tsk->gid != child->egid) || (tsk->gid != child->sgid) || (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) || (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + rmb(); + if (!child->dumpable && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/rtc.c linux/arch/sh/kernel/rtc.c --- v2.4.3/linux/arch/sh/kernel/rtc.c Thu Jan 4 15:25:55 2001 +++ linux/arch/sh/kernel/rtc.c Wed Apr 11 21:24:52 2001 @@ -7,6 +7,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/time.h> #include <asm/io.h> @@ -44,6 +45,8 @@ #define RMONAR 0xfffffeda #define RCR1 0xfffffedc #define RCR2 0xfffffede + +#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ #elif defined(__SH4__) /* SH-4 RTC */ #define R64CNT 0xffc80000 @@ -62,6 +65,8 @@ #define RMONAR 0xffc80034 #define RCR1 0xffc80038 #define RCR2 0xffc8003c + +#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ #endif #ifndef BCD_TO_BIN @@ -79,7 +84,7 @@ again: do { ctrl_outb(0, RCR1); /* Clear CF-bit */ - sec128 = ctrl_inb(RSECCNT); + sec128 = ctrl_inb(R64CNT); sec = ctrl_inb(RSECCNT); min = ctrl_inb(RMINCNT); hr = ctrl_inb(RHRCNT); @@ -96,6 +101,14 @@ #endif } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); +#if RTC_BIT_INVERTED != 0 + /* Work around to avoid reading correct value. */ + if (sec128 == RTC_BIT_INVERTED) { + schedule_timeout(1); + goto again; + } +#endif + BCD_TO_BIN(yr100); BCD_TO_BIN(yr); BCD_TO_BIN(mon); @@ -125,7 +138,7 @@ } tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec); - tv->tv_usec = (sec128 * 1000000) / 128; + tv->tv_usec = ((sec128 ^ RTC_BIT_INVERTED) * 1000000) / 128; } static int set_rtc_time(unsigned long nowtime) @@ -170,5 +183,9 @@ int sh_rtc_settimeofday(const struct timeval *tv) { +#if RTC_BIT_INVERTED != 0 + /* This is not accurate, but better than nothing. */ + schedule_timeout(HZ/2); +#endif return set_rtc_time(tv->tv_sec); } diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/semaphore.c linux/arch/sh/kernel/semaphore.c --- v2.4.3/linux/arch/sh/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/sh/kernel/semaphore.c Tue Apr 17 17:19:25 2001 @@ -135,162 +135,3 @@ { return waking_non_zero_trylock(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; -} - -struct rw_semaphore * __rwsem_wake(struct rw_semaphore *sem) -{ - if (atomic_read(&sem->count) == 0) - return rwsem_wake_writer(sem); - else - return rwsem_wake_readers(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; -} - -struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry) -{ - if (carry) { - int saved, new; - - do { - down_read_failed(sem); - saved = atomic_read(&sem->count); - if ((new = atomic_dec_return(&sem->count)) >= 0) - return sem; - } while (!(new < 0 && saved >=0)); - } - - return down_read_failed_biased(sem); -} - -struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry) -{ - if (carry) { - int saved, new; - - do { - down_write_failed(sem); - saved = atomic_read(&sem->count); - if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count) ) == 0) - return sem; - } while (!(new < 0 && saved >=0)); - } - - return down_write_failed_biased(sem); -} diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c --- v2.4.3/linux/arch/sh/kernel/setup.c Fri Feb 9 11:29:44 2001 +++ linux/arch/sh/kernel/setup.c Wed Apr 11 21:24:52 2001 @@ -50,6 +50,7 @@ struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 0, 0, }; struct screen_info screen_info; +unsigned char aux_device_present = 0xaa; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ @@ -61,6 +62,19 @@ struct sh_machine_vector sh_mv; #endif +/* We need this to satisfy some external references. */ +struct screen_info screen_info = { + 0, 25, /* orig-x, orig-y */ + 0, /* unused */ + 0, /* orig-video-page */ + 0, /* orig-video-mode */ + 80, /* orig-video-cols */ + 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 25, /* orig-video-lines */ + 0, /* orig-video-isVGA */ + 16 /* orig-video-points */ +}; + extern void fpu_init(void); extern int root_mountflags; extern int _text, _etext, _edata, _end; @@ -115,7 +129,7 @@ { "Kernel data", 0, 0 } }; -static unsigned long memory_start, memory_end; +unsigned long memory_start, memory_end; #ifdef CONFIG_SH_EARLY_PRINTK /* diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_cqreek.c linux/arch/sh/kernel/setup_cqreek.c --- v2.4.3/linux/arch/sh/kernel/setup_cqreek.c Mon Oct 2 11:57:34 2000 +++ linux/arch/sh/kernel/setup_cqreek.c Wed Apr 11 21:24:52 2001 @@ -1,4 +1,4 @@ -/* $Id: setup_cqreek.c,v 1.5 2000/09/18 05:51:24 gniibe Exp $ +/* $Id: setup_cqreek.c,v 1.6 2001/02/14 09:36:42 gniibe Exp $ * * arch/sh/kernel/setup_cqreek.c * @@ -18,6 +18,7 @@ #include <asm/irq.h> #include <asm/machvec.h> #include <asm/machvec_init.h> +#include <asm/rtc.h> #define BRIDGE_FEATURE 0x0002 @@ -247,5 +248,11 @@ mv_init_irq: init_cqreek_IRQ, mv_isa_port2addr: cqreek_port2addr, + + mv_ioremap: generic_ioremap, + mv_iounmap: generic_iounmap, + + mv_rtc_gettimeofday: sh_rtc_gettimeofday, + mv_rtc_settimeofday: sh_rtc_settimeofday, }; ALIAS_MV(cqreek) diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_dc.c linux/arch/sh/kernel/setup_dc.c --- v2.4.3/linux/arch/sh/kernel/setup_dc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/setup_dc.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,360 @@ +/* + * $Id: setup_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $ + * SEGA Dreamcast support + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/pci.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#define GAPSPCI_REGS 0x01001400 +#define GAPSPCI_DMA_BASE 0x01840000 +#define GAPSPCI_DMA_SIZE 32768 +#define GAPSPCI_BBA_CONFIG 0x01001600 + +#define GAPSPCI_IRQ 11 +#define GAPSPCI_INTC 0x005f6924 + +static int gapspci_dma_used; + +static struct pci_bus *pci_root_bus; + +static void disable_gapspci_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long intc; + + save_and_cli(flags); + intc = inl(GAPSPCI_INTC); + intc &= ~(1<<3); + outl(intc, GAPSPCI_INTC); + restore_flags(flags); +} + + +static void enable_gapspci_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long intc; + + save_and_cli(flags); + intc = inl(GAPSPCI_INTC); + intc |= (1<<3); + outl(intc, GAPSPCI_INTC); + restore_flags(flags); +} + + +static void mask_and_ack_gapspci_irq(unsigned int irq) +{ + unsigned long flags; + unsigned long intc; + + save_and_cli(flags); + intc = inl(GAPSPCI_INTC); + intc &= ~(1<<3); + outl(intc, GAPSPCI_INTC); + restore_flags(flags); +} + + +static void end_gapspci_irq(unsigned int irq) +{ + enable_gapspci_irq(irq); +} + + +static unsigned int startup_gapspci_irq(unsigned int irq) +{ + enable_gapspci_irq(irq); + return 0; +} + + +static void shutdown_gapspci_irq(unsigned int irq) +{ + disable_gapspci_irq(irq); +} + + +static struct hw_interrupt_type gapspci_irq_type = { + "GAPSPCI-IRQ", + startup_gapspci_irq, + shutdown_gapspci_irq, + enable_gapspci_irq, + disable_gapspci_irq, + mask_and_ack_gapspci_irq, + end_gapspci_irq +}; + + +static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) +{ + return PCI_SLOT(dev->devfn); +} + +static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return GAPSPCI_IRQ; +} + +int __init setup_dreamcast(void) +{ + gapspci_init(); + + printk(KERN_INFO "SEGA Dreamcast support.\n"); +#if 0 + printk(KERN_INFO "BCR1: 0x%08x\n", ctrl_inl(0xff800000)); + printk(KERN_INFO "BCR2: 0x%08x\n", ctrl_inw(0xff800004)); + printk(KERN_INFO "WCR1: 0x%08x\n", ctrl_inl(0xff800008)); + printk(KERN_INFO "WCR2: 0x%08x\n", ctrl_inl(0xff80000c)); + printk(KERN_INFO "WCR3: 0x%08x\n", ctrl_inl(0xff800010)); + printk(KERN_INFO "MCR: 0x%08x\n", ctrl_inl(0xff800014)); + printk(KERN_INFO "PCR: 0x%08x\n", ctrl_inw(0xff800018)); +/* + * BCR1: 0xa3020008 + * BCR2: 0x0001 + * WCR1: 0x01110111 + * WCR2: 0x618066d8 + * WCR3: 0x07777777 + * MCR: 0xc00a0e24 + * PCR: 0x0000 + */ +#endif + return 0; +} + + +/* + * Dreamcast PCI: Supports SEGA Broadband Adaptor only. + */ + +#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0) + +static int gapspci_read_config_byte(struct pci_dev *dev, int where, + u8 * val) +{ + if (BBA_SELECTED(dev)) + *val = inb(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xff; + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_read_config_word(struct pci_dev *dev, int where, + u16 * val) +{ + if (BBA_SELECTED(dev)) + *val = inw(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_read_config_dword(struct pci_dev *dev, int where, + u32 * val) +{ + if (BBA_SELECTED(dev)) + *val = inl(GAPSPCI_BBA_CONFIG+where); + else + *val = 0xffffffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_write_config_byte(struct pci_dev *dev, int where, + u8 val) +{ + if (BBA_SELECTED(dev)) + outb(val, GAPSPCI_BBA_CONFIG+where); + + return PCIBIOS_SUCCESSFUL; +} + + +static int gapspci_write_config_word(struct pci_dev *dev, int where, + u16 val) +{ + if (BBA_SELECTED(dev)) + outw(val, GAPSPCI_BBA_CONFIG+where); + + return PCIBIOS_SUCCESSFUL; +} + +static int gapspci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + if (BBA_SELECTED(dev)) + outl(val, GAPSPCI_BBA_CONFIG+where); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_config_ops = { + gapspci_read_config_byte, + gapspci_read_config_word, + gapspci_read_config_dword, + gapspci_write_config_byte, + gapspci_write_config_word, + gapspci_write_config_dword +}; + + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ +} + + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ +} + + +void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ +} + + +int 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 (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 *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t * dma_handle) +{ + unsigned long buf; + + if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE) + return NULL; + + buf = GAPSPCI_DMA_BASE+gapspci_dma_used; + + gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size); + + printk("pci_alloc_consistent: %d bytes at 0x%08x\n", size, buf); + + *dma_handle = (dma_addr_t)buf; + + return (void *)P2SEGADDR(buf); +} + + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ +} + + +void __init +pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) +{ +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + struct list_head *ln; + struct pci_dev *dev; + + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + dev = pci_dev_b(ln); + if (!BBA_SELECTED(dev)) continue; + + printk("PCI: MMIO fixup to %s\n", dev->name); + dev->resource[1].start=0x01001700; + dev->resource[1].end=0x010017ff; + } +} + + +void __init dreamcast_pcibios_init(void) +{ + pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); + /* pci_assign_unassigned_resources(); */ + pci_fixup_irqs(no_swizzle, map_od_irq); +} + + +static __init int gapspci_init(void) +{ + int i; + char idbuf[16]; + + for(i=0; i<16; i++) + idbuf[i]=inb(GAPSPCI_REGS+i); + + if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16)) + return -1; + + outl(0x5a14a501, GAPSPCI_REGS+0x18); + + for(i=0; i<1000000; i++); + + if(inl(GAPSPCI_REGS+0x18)!=1) + return -1; + + outl(0x01000000, GAPSPCI_REGS+0x20); + outl(0x01000000, GAPSPCI_REGS+0x24); + + outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); + outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); + + outl(1, GAPSPCI_REGS+0x14); + outl(1, GAPSPCI_REGS+0x34); + + gapspci_dma_used=0; + + /* */ + irq_desc[GAPSPCI_IRQ].handler = &gapspci_irq_type; + + /* Setting Broadband Adapter */ + outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); + outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); + outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); + outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); + outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); + outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); + outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); + + return 0; +} diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_ec3104.c linux/arch/sh/kernel/setup_ec3104.c --- v2.4.3/linux/arch/sh/kernel/setup_ec3104.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/setup_ec3104.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,242 @@ +/* + * linux/arch/sh/kernel/setup_ec3104.c + * EC3104 companion chip support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/types.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ec3104.h> + +/* This is for debugging mostly; here's the table that I intend to keep + * in here: + * + * index function base addr power interrupt bit + * 0 power b0ec0000 --- 00000001 (unused) + * 1 irqs b0ec1000 --- 00000002 (unused) + * 2 ?? b0ec2000 b0ec0008 00000004 + * 3 PS2 (1) b0ec3000 b0ec000c 00000008 + * 4 PS2 (2) b0ec4000 b0ec0010 00000010 + * 5 ?? b0ec5000 b0ec0014 00000020 + * 6 I2C b0ec6000 b0ec0018 00000040 + * 7 serial (1) b0ec7000 b0ec001c 00000080 + * 8 serial (2) b0ec8000 b0ec0020 00000100 + * 9 serial (3) b0ec9000 b0ec0024 00000200 + * 10 serial (4) b0eca000 b0ec0028 00000400 + * 12 GPIO (1) b0ecc000 b0ec0030 + * 13 GPIO (2) b0ecc000 b0ec0030 + * 16 pcmcia (1) b0ed0000 b0ec0040 00010000 + * 17 pcmcia (2) b0ed1000 b0ec0044 00020000 + */ + +/* I used the register names from another interrupt controller I worked with, + * since it seems to be identical to the ec3104 except that all bits are + * inverted: + * + * IRR: Interrupt Request Register (pending and enabled interrupts) + * IMR: Interrupt Mask Register (which interrupts are enabled) + * IPR: Interrupt Pending Register (pending interrupts, even disabled ones) + * + * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all + * IRQs seem to be level-triggered. + */ + +#define EC3104_IRR (EC3104_BASE + 0x1000) +#define EC3104_IMR (EC3104_BASE + 0x1004) +#define EC3104_IPR (EC3104_BASE + 0x1008) + +#define ctrl_readl(addr) (*(volatile u32 *)(addr)) +#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data)) +#define ctrl_readb(addr) (*(volatile u8 *)(addr)) + +static char *ec3104_name(unsigned index) +{ + switch(index) { + case 0: + return "power management"; + case 1: + return "interrupts"; + case 3: + return "PS2 (1)"; + case 4: + return "PS2 (2)"; + case 5: + return "I2C (1)"; + case 6: + return "I2C (2)"; + case 7: + return "serial (1)"; + case 8: + return "serial (2)"; + case 9: + return "serial (3)"; + case 10: + return "serial (4)"; + case 16: + return "pcmcia (1)"; + case 17: + return "pcmcia (2)"; + default: { + static char buf[32]; + + sprintf(buf, "unknown (%d)", index); + + return buf; + } + } +} + +int get_pending_interrupts(char *buf) +{ + u32 ipr; + u32 bit; + char *p = buf; + + p += sprintf(p, "pending: ("); + + ipr = ctrl_inl(EC3104_IPR); + + for (bit = 1; bit < 32; bit++) + if (!(ipr & (1<<bit))) + p += sprintf(p, "%s ", ec3104_name(bit)); + + p += sprintf(p, ")\n"); + + return p - buf; +} + +static inline u32 ec3104_irq2mask(unsigned int irq) +{ + return (1 << (irq - EC3104_IRQBASE)); +} + +static inline void mask_ec3104_irq(unsigned int irq) +{ + u32 mask; + + mask = ctrl_readl(EC3104_IMR); + + mask |= ec3104_irq2mask(irq); + + ctrl_writel(mask, EC3104_IMR); +} + +static inline void unmask_ec3104_irq(unsigned int irq) +{ + u32 mask; + + mask = ctrl_readl(EC3104_IMR); + + mask &= ~ec3104_irq2mask(irq); + + ctrl_writel(mask, EC3104_IMR); +} + +static void disable_ec3104_irq(unsigned int irq) +{ + mask_ec3104_irq(irq); +} + +static void enable_ec3104_irq(unsigned int irq) +{ + unmask_ec3104_irq(irq); +} + +static void mask_and_ack_ec3104_irq(unsigned int irq) +{ + mask_ec3104_irq(irq); +} + +static void end_ec3104_irq(unsigned int irq) +{ + unmask_ec3104_irq(irq); +} + +static unsigned int startup_ec3104_irq(unsigned int irq) +{ + unmask_ec3104_irq(irq); + + return 0; +} + +static void shutdown_ec3104_irq(unsigned int irq) +{ + mask_ec3104_irq(irq); + +} + +static struct hw_interrupt_type ec3104_int = { + typename: "EC3104", + enable: enable_ec3104_irq, + disable: disable_ec3104_irq, + ack: mask_and_ack_ec3104_irq, + end: end_ec3104_irq, + startup: startup_ec3104_irq, + shutdown: shutdown_ec3104_irq, +}; + +/* Yuck. the _demux API is ugly */ +int ec3104_irq_demux(int irq) +{ + if (irq == EC3104_IRQ) { + unsigned int mask; + + mask = ctrl_readl(EC3104_IRR); + + if (mask == 0xffffffff) + return EC3104_IRQ; + else + return EC3104_IRQBASE + ffz(mask); + } + + return irq; +} + +int __init setup_ec3104(void) +{ + char str[8]; + int i; + + if (!MACH_EC3104) + printk("!MACH_EC3104\n"); + + if (0) + return 0; + + for (i=0; i<8; i++) + str[i] = ctrl_readb(EC3104_BASE + i); + + for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++) + irq_desc[i].handler = &ec3104_int; + + printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n", + str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE); + + + /* mask all interrupts. this should have been done by the boot + * loader for us but we want to be sure ... */ + ctrl_writel(0xffffffff, EC3104_IMR); + + return 0; +} + +module_init(setup_ec3104); diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_hd64461.c linux/arch/sh/kernel/setup_hd64461.c --- v2.4.3/linux/arch/sh/kernel/setup_hd64461.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/setup_hd64461.c Wed Apr 11 21:24:52 2001 @@ -88,7 +88,7 @@ static void hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_INFO - "HD64461: spurious interrupt, nirr: 0x%lx nimr: 0x%lx\n", + "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n", inw(HD64461_NIRR), inw(HD64461_NIMR)); } @@ -104,7 +104,7 @@ if (irq == 16) irq = CONFIG_HD64461_IRQ; else irq += HD64461_IRQBASE; } - return irq; + return __irq_demux(irq); } static struct irqaction irq0 = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL}; @@ -120,10 +120,9 @@ printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n", CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE, HD64461_IRQBASE+15); -#ifdef CONFIG_CPU_SUBTYPE_SH7709 - /* IRQ line for HD64461 should be set level trigger mode("10"). */ - /* And this should be done earlier than the kernel starts. */ - ctrl_outw(0x0200, INTC_ICR1); /* when connected to IRQ4. */ + +#if defined(CONFIG_CPU_SUBTYPE_SH7709) /* Should be at processor specific part.. */ + outw(0x2240, INTC_ICR1); #endif outw(0xffff, HD64461_NIMR); @@ -135,7 +134,7 @@ #ifdef CONFIG_HD64461_ENABLER printk(KERN_INFO "HD64461: enabling PCMCIA devices\n"); - outb(0x04, HD64461_PCC1CSCIER); + outb(0x4c, HD64461_PCC1CSCIER); outb(0x00, HD64461_PCC1CSCR); #endif diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/setup_hd64465.c linux/arch/sh/kernel/setup_hd64465.c --- v2.4.3/linux/arch/sh/kernel/setup_hd64465.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/setup_hd64465.c Wed Apr 11 21:24:52 2001 @@ -0,0 +1,207 @@ +/* + * $Id: setup_hd64465.c,v 1.3 2001/02/07 17:52:53 stuart_menefy Exp $ + * + * Setup and IRQ handling code for the HD64465 companion chip. + * by Greg Banks <gbanks@pocketpenguins.com> + * Copyright (c) 2000 PocketPenguins Inc + * + * Derived from setup_hd64461.c which bore the message: + * Copyright (C) 2000 YAEGASHI Takeshi + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include <asm/hd64465.h> + +#undef HD64465_DEBUG + +#ifdef HD64465_DEBUG +#define DPRINTK(args...) printk(args) +#else +#define DPRINTK(args...) +#endif + +static void disable_hd64465_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short nimr; + unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); + + DPRINTK("disable_hd64465_irq(%d): mask=%x\n", irq, mask); + save_and_cli(flags); + nimr = inw(HD64465_REG_NIMR); + nimr |= mask; + outw(nimr, HD64465_REG_NIMR); + restore_flags(flags); +} + + +static void enable_hd64465_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short nimr; + unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); + + DPRINTK("enable_hd64465_irq(%d): mask=%x\n", irq, mask); + save_and_cli(flags); + nimr = inw(HD64465_REG_NIMR); + nimr &= ~mask; + outw(nimr, HD64465_REG_NIMR); + restore_flags(flags); +} + + +static void mask_and_ack_hd64465(unsigned int irq) +{ + disable_hd64465_irq(irq); +} + + +static void end_hd64465_irq(unsigned int irq) +{ + enable_hd64465_irq(irq); +} + + +static unsigned int startup_hd64465_irq(unsigned int irq) +{ + enable_hd64465_irq(irq); + return 0; +} + + +static void shutdown_hd64465_irq(unsigned int irq) +{ + disable_hd64465_irq(irq); +} + + +static struct hw_interrupt_type hd64465_irq_type = { + typename: "HD64465-IRQ", + startup: startup_hd64465_irq, + shutdown: shutdown_hd64465_irq, + enable: enable_hd64465_irq, + disable: disable_hd64465_irq, + ack: mask_and_ack_hd64465, + end: end_hd64465_irq +}; + + +static void hd64465_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO + "HD64465: spurious interrupt, nirr: 0x%x nimr: 0x%x\n", + inw(HD64465_REG_NIRR), inw(HD64465_REG_NIMR)); +} + + +/*====================================================*/ + +/* + * Support for a secondary IRQ demux step. This is necessary + * because the HD64465 presents a very thin interface to the + * PCMCIA bus; a lot of features (such as remapping interrupts) + * normally done in hardware by other PCMCIA host bridges is + * instead done in software. + */ +static struct +{ + int (*func)(int, void *); + void *dev; +} hd64465_demux[HD64465_IRQ_NUM]; + +void hd64465_register_irq_demux(int irq, + int (*demux)(int irq, void *dev), void *dev) +{ + hd64465_demux[irq - HD64465_IRQ_BASE].func = demux; + hd64465_demux[irq - HD64465_IRQ_BASE].dev = dev; +} +EXPORT_SYMBOL(hd64465_register_irq_demux); + +void hd64465_unregister_irq_demux(int irq) +{ + hd64465_demux[irq - HD64465_IRQ_BASE].func = 0; +} +EXPORT_SYMBOL(hd64465_unregister_irq_demux); + + + +int hd64465_irq_demux(int irq) +{ + if (irq == CONFIG_HD64465_IRQ) { + unsigned short i, bit; + unsigned short nirr = inw(HD64465_REG_NIRR); + unsigned short nimr = inw(HD64465_REG_NIMR); + + DPRINTK("hd64465_irq_demux, nirr=%04x, nimr=%04x\n", nirr, nimr); + nirr &= ~nimr; + for (bit = 1, i = 0 ; i < HD64465_IRQ_NUM ; bit <<= 1, i++) + if (nirr & bit) + break; + + if (i < HD64465_IRQ_NUM) { + irq = HD64465_IRQ_BASE + i; + if (hd64465_demux[i].func != 0) + irq = hd64465_demux[i].func(irq, hd64465_demux[i].dev); + } + } + return irq; +} + +static struct irqaction irq0 = { hd64465_interrupt, SA_INTERRUPT, 0, "HD64465", NULL, NULL}; + + +static int __init setup_hd64465(void) +{ + int i; + unsigned short rev; + unsigned short smscr; + + if (!MACH_HD64465) + return 0; + + printk(KERN_INFO "HD64465 configured at 0x%x on irq %d(mapped into %d to %d)\n", + CONFIG_HD64465_IOBASE, + CONFIG_HD64465_IRQ, + HD64465_IRQ_BASE, + HD64465_IRQ_BASE+HD64465_IRQ_NUM-1); + + if (inw(HD64465_REG_SDID) != HD64465_SDID) { + printk(KERN_ERR "HD64465 device ID not found, check base address\n"); + } + + rev = inw(HD64465_REG_SRR); + printk(KERN_INFO "HD64465 hardware revision %d.%d\n", (rev >> 8) & 0xff, rev & 0xff); + + outw(0xffff, HD64465_REG_NIMR); /* mask all interrupts */ + + for (i = 0; i < HD64465_IRQ_NUM ; i++) { + irq_desc[HD64465_IRQ_BASE + i].handler = &hd64465_irq_type; + } + + setup_irq(CONFIG_HD64465_IRQ, &irq0); + +#ifdef CONFIG_SERIAL + /* wake up the UART from STANDBY at this point */ + smscr = inw(HD64465_REG_SMSCR); + outw(smscr & (~HD64465_SMSCR_UARTST), HD64465_REG_SMSCR); + + /* remap IO ports for first ISA serial port to HD64465 UART */ + hd64465_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1); +#endif + + return 0; +} + +module_init(setup_hd64465); diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/sh_ksyms.c linux/arch/sh/kernel/sh_ksyms.c --- v2.4.3/linux/arch/sh/kernel/sh_ksyms.c Fri Mar 2 11:15:47 2001 +++ linux/arch/sh/kernel/sh_ksyms.c Wed Apr 11 21:24:52 2001 @@ -17,6 +17,7 @@ #include <asm/io.h> #include <asm/hardirq.h> #include <asm/delay.h> +#include <asm/pgalloc.h> #include <linux/irq.h> extern void dump_thread(struct pt_regs *, struct user *); @@ -45,6 +46,7 @@ EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); /* mem exports */ EXPORT_SYMBOL(memchr); diff -u --recursive --new-file v2.4.3/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.4.3/linux/arch/sh/kernel/time.c Thu Jan 4 13:19:13 2001 +++ linux/arch/sh/kernel/time.c Wed Apr 11 21:24:52 2001 @@ -57,6 +57,13 @@ #define TMU0_TCR 0xffd80010 /* Word access */ #define FRQCR 0xffc00000 + +/* Core Processor Version Register */ +#define CCN_PVR 0xff000030 +#define CCN_PVR_CHIP_SHIFT 24 +#define CCN_PVR_CHIP_MASK 0xff +#define CCN_PVR_CHIP_ST40STB1 0x4 + #endif extern rwlock_t xtime_lock; @@ -289,13 +296,62 @@ static int ifc_table[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; #define bfc_table ifc_table /* Same */ static int pfc_table[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; + +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 + struct frqcr_data { + unsigned short frqcr; + struct { + unsigned char multiplier; + unsigned char divisor; + } factor[3]; + }; + + static struct frqcr_data st40_frqcr_table[] = { + { 0x000, {{1,1}, {1,1}, {1,2}}}, + { 0x002, {{1,1}, {1,1}, {1,4}}}, + { 0x004, {{1,1}, {1,1}, {1,8}}}, + { 0x008, {{1,1}, {1,2}, {1,2}}}, + { 0x00A, {{1,1}, {1,2}, {1,4}}}, + { 0x00C, {{1,1}, {1,2}, {1,8}}}, + { 0x011, {{1,1}, {2,3}, {1,6}}}, + { 0x013, {{1,1}, {2,3}, {1,3}}}, + { 0x01A, {{1,1}, {1,2}, {1,4}}}, + { 0x01C, {{1,1}, {1,2}, {1,8}}}, + { 0x023, {{1,1}, {2,3}, {1,3}}}, + { 0x02C, {{1,1}, {1,2}, {1,8}}}, + { 0x048, {{1,2}, {1,2}, {1,4}}}, + { 0x04A, {{1,2}, {1,2}, {1,6}}}, + { 0x04C, {{1,2}, {1,2}, {1,8}}}, + { 0x05A, {{1,2}, {1,3}, {1,6}}}, + { 0x05C, {{1,2}, {1,3}, {1,6}}}, + { 0x063, {{1,2}, {1,4}, {1,4}}}, + { 0x06C, {{1,2}, {1,4}, {1,8}}}, + { 0x091, {{1,3}, {1,3}, {1,6}}}, + { 0x093, {{1,3}, {1,3}, {1,6}}}, + { 0x0A3, {{1,3}, {1,6}, {1,6}}}, + { 0x0DA, {{1,4}, {1,4}, {1,8}}}, + { 0x0DC, {{1,4}, {1,4}, {1,8}}}, + { 0x0EC, {{1,4}, {1,8}, {1,8}}}, + { 0x123, {{1,4}, {1,4}, {1,8}}}, + { 0x16C, {{1,4}, {1,8}, {1,8}}}, + }; +#endif #endif +#if defined(CONFIG_SH_DREAMCAST) + xtime.tv_sec = 0; + xtime.tv_usec = 0; +#else rtc_gettimeofday(&xtime); +#endif setup_irq(TIMER_IRQ, &irq0); +#if defined(CONFIG_SH_DREAMCAST) + timer_freq = 50*1000*1000/4; +#else timer_freq = get_timer_frequency(); +#endif module_clock = timer_freq * 4; @@ -316,15 +372,53 @@ } #elif defined(__SH4__) { + unsigned long pvr; frqcr = ctrl_inw(FRQCR); - ifc = ifc_table[(frqcr>> 6) & 0x0007]; - bfc = bfc_table[(frqcr>> 3) & 0x0007]; - pfc = pfc_table[frqcr & 0x0007]; + +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 + /* This should probably be moved into the SH3 probing code, and then use the processor + * structure to determine which CPU we are running on. + */ + pvr = ctrl_inl(CCN_PVR); + printk("PVR %08x\n", pvr); + + if (((pvr >>CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { + /* Unfortunatly the STB1 FRQCR values are different from the 7750 ones */ + struct frqcr_data *d; + int a; + + for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { + d = &st40_frqcr_table[a]; + if (d->frqcr == (frqcr & 0x1ff)) + break; + } + if (a == ARRAY_SIZE(st40_frqcr_table)) { + d = st40_frqcr_table; + printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); + } + + printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Periph: %d/%d\n", + d->factor[0].multiplier, d->factor[0].divisor, + d->factor[1].multiplier, d->factor[1].divisor, + d->factor[2].multiplier, d->factor[2].divisor); + + master_clock = module_clock * d->factor[2].divisor / d->factor[2].multiplier; + bus_clock = master_clock * d->factor[1].multiplier / d->factor[1].divisor; + cpu_clock = master_clock * d->factor[0].multiplier / d->factor[0].divisor; + goto skip_calc; + } else +#endif + { + ifc = ifc_table[(frqcr>> 6) & 0x0007]; + bfc = bfc_table[(frqcr>> 3) & 0x0007]; + pfc = pfc_table[frqcr & 0x0007]; + } } #endif master_clock = module_clock * pfc; bus_clock = master_clock / bfc; cpu_clock = master_clock / ifc; + skip_calc: printk("CPU clock: %d.%02dMHz\n", (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); printk("Bus clock: %d.%02dMHz\n", diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c --- v2.4.3/linux/arch/sh/mm/cache.c Sun Jan 28 18:56:00 2001 +++ linux/arch/sh/mm/cache.c Wed Apr 11 21:24:52 2001 @@ -148,7 +148,13 @@ cpu_data->type = CPU_SH7729; } #elif defined(__SH4__) +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 + cpu_data->type = CPU_ST40STB1; +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) cpu_data->type = CPU_SH7750; +#else +#error Unknown SH4 CPU type +#endif #endif } diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/extable.c linux/arch/sh/mm/extable.c --- v2.4.3/linux/arch/sh/mm/extable.c Wed Nov 10 08:31:37 1999 +++ linux/arch/sh/mm/extable.c Wed Apr 11 21:24:52 2001 @@ -46,7 +46,7 @@ /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) + if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); diff -u --recursive --new-file v2.4.3/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c --- v2.4.3/linux/arch/sh/mm/init.c Tue Nov 28 22:43:39 2000 +++ linux/arch/sh/mm/init.c Wed Apr 11 21:24:52 2001 @@ -45,104 +45,25 @@ extern unsigned long init_smp_mappings(unsigned long); -/* - * 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. - */ - -unsigned long empty_bad_page[1024]; -pte_t empty_bad_pte_table[PTRS_PER_PTE]; extern unsigned long empty_zero_page[1024]; -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; -} - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); - return pte + offset; - } - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - unsigned long pte; - - pte = (unsigned long) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page((void *)pte); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); - return (pte_t *)pte + offset; - } - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); - return NULL; - } - free_page(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; if (pgtable_cache_size > high) { do { - if (pgd_quicklist) - free_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++; + 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/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c --- v2.4.3/linux/arch/sh/mm/ioremap.c Fri Oct 13 12:06:52 2000 +++ linux/arch/sh/mm/ioremap.c Wed Apr 11 21:24:52 2001 @@ -25,14 +25,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, @@ -45,38 +49,48 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; phys_addr -= address; + 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); 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) + unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; phys_addr -= address; - dir = pgd_offset_k(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; + 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; } /* @@ -106,7 +120,7 @@ /* * Don't remap the low PCI/ISA area, it's always mapped.. */ - if (phys_addr >= 0xA0000 && last_addr <= 0x100000) + if (phys_addr >= 0xA0000 && last_addr < 0x100000) return phys_to_virt(phys_addr); /* diff -u --recursive --new-file v2.4.3/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.4.3/linux/arch/sparc/config.in Sun Feb 18 19:49:44 2001 +++ linux/arch/sparc/config.in Tue Apr 17 17:19:25 2001 @@ -48,6 +48,8 @@ define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 if [ "$CONFIG_SUN4" != "y" ]; then diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.4.3/linux/arch/sparc/kernel/irq.c Sun Feb 18 19:49:44 2001 +++ linux/arch/sparc/kernel/irq.c Fri Apr 13 20:26:07 2001 @@ -8,7 +8,7 @@ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) - * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org) */ #include <linux/config.h> diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/semaphore.c linux/arch/sparc/kernel/semaphore.c --- v2.4.3/linux/arch/sparc/kernel/semaphore.c Mon Jan 22 13:30:20 2001 +++ linux/arch/sparc/kernel/semaphore.c Tue Apr 17 17:19:26 2001 @@ -151,119 +151,3 @@ spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } - -/* rw mutexes - * Implemented by Jakub Jelinek (jakub@redhat.com) based on - * i386 implementation by Ben LaHaise (bcrl@redhat.com). - */ - -extern inline int ldstub(unsigned char *p) -{ - int ret; - asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory"); - return ret; -} - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - DECLARE_WAITQUEUE(wait, tsk); - -void down_read_failed_biased(struct rw_semaphore *sem) -{ - DOWN_VAR - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (!ldstub(&sem->read_not_granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (sem->read_not_granted) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -void down_write_failed_biased(struct rw_semaphore *sem) -{ - DOWN_VAR - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (!ldstub(&sem->write_not_granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (sem->write_not_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); -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -void down_read_failed(struct rw_semaphore *sem) -{ - DOWN_VAR - - __up_read(sem); /* this takes care of granting the lock */ - - 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. Since we're - * a writer, we'll make ourselves exclusive. - */ -void down_write_failed(struct rw_semaphore *sem) -{ - DOWN_VAR - - __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; -} - -void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) -{ - if (readers) { - /* Due to lame ldstub we don't do here - a BUG() consistency check */ - sem->read_not_granted = 0; - wake_up(&sem->wait); - } else { - sem->write_not_granted = 0; - wake_up(&sem->write_bias_wait); - } -} diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.4.3/linux/arch/sparc/kernel/setup.c Sun Feb 18 19:49:54 2001 +++ linux/arch/sparc/kernel/setup.c Fri Apr 13 20:26:07 2001 @@ -2,7 +2,7 @@ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #include <linux/errno.h> diff -u --recursive --new-file v2.4.3/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.4.3/linux/arch/sparc/kernel/sys_sparc.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc/kernel/sys_sparc.c Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.68 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sparc.c,v 1.70 2001/04/14 01:12:02 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -36,19 +36,28 @@ #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) -unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +unsigned long 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 (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) + return -EINVAL; + return addr; + } + /* See asm-sparc/uaccess.h */ if (len > TASK_SIZE - PAGE_SIZE) - return 0; + return -ENOMEM; if (ARCH_SUN4C_SUN4 && len > 0x20000000) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -60,11 +69,11 @@ vmm = find_vma(current->mm, PAGE_OFFSET); } if (TASK_SIZE - PAGE_SIZE - len < addr) - return 0; + return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); } } @@ -233,15 +242,10 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (flags & MAP_SHARED) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; - down_write(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - out_putf: if (file) fput(file); @@ -285,9 +289,6 @@ new_len > TASK_SIZE - PAGE_SIZE) goto out; down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); - if (vma && (vma->vm_flags & VM_SHARED)) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (ARCH_SUN4C_SUN4 && new_addr < 0xe0000000 && @@ -298,17 +299,30 @@ } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && addr + new_len > 0x20000000) || addr + new_len > TASK_SIZE - PAGE_SIZE) { + unsigned long map_flags = 0; + struct file *file = NULL; + ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area (addr, new_len); - if (!new_addr) + + vma = find_vma(current->mm, addr); + if (vma) { + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + file = vma->vm_file; + } + + new_addr = get_unmapped_area(file, addr, new_len, + vma ? vma->vm_pgoff : 0, + map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up_write(¤t->mm->mmap_sem); out: return ret; diff -u --recursive --new-file v2.4.3/linux/arch/sparc/lib/memset.S linux/arch/sparc/lib/memset.S --- v2.4.3/linux/arch/sparc/lib/memset.S Mon Jun 19 17:59:38 2000 +++ linux/arch/sparc/lib/memset.S Thu Apr 12 12:10:25 2001 @@ -188,7 +188,7 @@ b 30f add %o0, %o1, %o0 30: -/* %o4 is faulting address, %o5 is %pc where fault occured */ +/* %o4 is faulting address, %o5 is %pc where fault occurred */ save %sp, -104, %sp mov %i5, %o0 mov %i7, %o1 diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c --- v2.4.3/linux/arch/sparc/mm/generic.c Wed Aug 9 13:49:55 2000 +++ linux/arch/sparc/mm/generic.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.10 2000/08/09 00:00:15 davem Exp $ +/* $Id: generic.c,v 1.12 2001/04/09 21:40:46 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -21,11 +21,7 @@ struct page *ptpage = pte_page(page); if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) return; - /* - * free_page() used to be able to clear swap cache - * entries. We may now have to do it manually. - */ - free_page_and_swap_cache(ptpage); + page_cache_release(ptpage); return; } swap_free(pte_to_swp_entry(page)); diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.4.3/linux/arch/sparc/mm/init.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc/mm/init.c Fri Apr 13 20:26:07 2001 @@ -1,10 +1,10 @@ -/* $Id: init.c,v 1.97 2001/02/26 02:57:34 anton Exp $ +/* $Id: init.c,v 1.96 2000/11/30 08:51:50 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #include <linux/config.h> diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.4.3/linux/arch/sparc/mm/srmmu.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc/mm/srmmu.c Fri Apr 13 20:26:07 2001 @@ -5,7 +5,7 @@ * Copyright (C) 1995 Pete Zaitcev * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1999,2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1999,2000 Anton Blanchard (anton@samba.org) */ #include <linux/config.h> diff -u --recursive --new-file v2.4.3/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.4.3/linux/arch/sparc/mm/sun4c.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc/mm/sun4c.c Fri Apr 13 20:26:07 2001 @@ -4,7 +4,7 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) - * Copyright (C) 1997-2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.3/linux/arch/sparc64/config.in Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/config.in Tue Apr 17 17:19:26 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.136 2001/03/24 06:04:24 davem Exp $ +# $Id: config.in,v 1.139 2001/04/03 12:29:38 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -21,6 +21,8 @@ mainmenu_option next_comment comment 'General setup' +tristate 'UltraSPARC-III bootbus i2c controller driver' CONFIG_BBC_I2C + define_bool CONFIG_VT y define_bool CONFIG_VT_CONSOLE y @@ -31,6 +33,8 @@ # Global things across all Sun machines. define_bool CONFIG_HAVE_DEC_LOCK y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n define_bool CONFIG_ISA n define_bool CONFIG_EISA n define_bool CONFIG_MCA n diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.3/linux/arch/sparc64/defconfig Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/defconfig Fri Apr 13 20:15:55 2001 @@ -17,6 +17,7 @@ # # General setup # +CONFIG_BBC_I2C=m CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_SMP is not set @@ -445,6 +446,7 @@ CONFIG_EFS_FS=m # CONFIG_JFFS_FS is not set CONFIG_CRAMFS=m +# CONFIG_TMPFS is not set CONFIG_RAMFS=m CONFIG_ISO9660_FS=m CONFIG_JOLIET=y @@ -519,11 +521,13 @@ # CONFIG_NLS_CODEPAGE_865 is not set # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_CODEPAGE_932 is not set # CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -531,11 +535,12 @@ # CONFIG_NLS_ISO8859_5 is not set # CONFIG_NLS_ISO8859_6 is not set # CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set # @@ -606,7 +611,6 @@ # USB Serial Converter support # CONFIG_USB_SERIAL=m -# CONFIG_USB_SERIAL_DEBUG is not set CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_BELKIN=m CONFIG_USB_SERIAL_WHITEHEAT=m diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.4.3/linux/arch/sparc64/kernel/Makefile Tue Mar 6 22:44:16 2001 +++ linux/arch/sparc64/kernel/Makefile Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.64 2001/02/28 05:59:45 davem Exp $ +# $Id: Makefile,v 1.66 2001/04/03 12:29:38 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -24,7 +24,7 @@ traps.o devices.o auxio.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ - power.o sbus.o iommu_common.o sparc64_ksyms.o + power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o obj-$(CONFIG_PCI) += ebus.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/chmc.c linux/arch/sparc64/kernel/chmc.c --- v2.4.3/linux/arch/sparc64/kernel/chmc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/chmc.c Thu Apr 12 12:10:25 2001 @@ -0,0 +1,451 @@ +/* $Id: chmc.c,v 1.3 2001/04/03 12:49:47 davem Exp $ + * memctrlr.c: Driver for UltraSPARC-III memory controller. + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/init.h> +#include <asm/spitfire.h> +#include <asm/chmctrl.h> +#include <asm/oplib.h> +#include <asm/io.h> + +#define CHMCTRL_NDGRPS 2 +#define CHMCTRL_NDIMMS 4 + +#define DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS) + +/* OBP memory-layout property format. */ +struct obp_map { + unsigned char dimm_map[144]; + unsigned char pin_map[576]; +}; + +#define DIMM_LABEL_SZ 8 + +struct obp_mem_layout { + /* One max 8-byte string label per DIMM. Usually + * this matches the label on the motherboard where + * that DIMM resides. + */ + char dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ]; + + /* If symmetric use map[0], else it is + * asymmetric and map[1] should be used. + */ + char symmetric; + + struct obp_map map[2]; +}; + +#define CHMCTRL_NBANKS 4 + +struct bank_info { + struct mctrl_info *mp; + int bank_id; + + u64 raw_reg; + int valid; + int uk; + int um; + int lk; + int lm; + int interleave; + unsigned long base; + unsigned long size; +}; + +struct mctrl_info { + struct list_head list; + int portid; + int index; + + struct obp_mem_layout layout_prop; + int layout_size; + + void *regs; + + u64 timing_control1; + u64 timing_control2; + u64 timing_control3; + u64 timing_control4; + u64 memaddr_control; + + struct bank_info logical_banks[CHMCTRL_NBANKS]; +}; + +static LIST_HEAD(mctrl_list); + +/* Does BANK decode PHYS_ADDR? */ +static int bank_match(struct bank_info *bp, unsigned long phys_addr) +{ + unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT; + unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT; + + /* Bank must be enabled to match. */ + if (bp->valid == 0) + return 0; + + /* Would BANK match upper bits? */ + upper_bits ^= bp->um; /* What bits are different? */ + upper_bits = ~upper_bits; /* Invert. */ + upper_bits |= bp->uk; /* What bits don't matter for matching? */ + upper_bits = ~upper_bits; /* Invert. */ + + if (upper_bits) + return 0; + + /* Would BANK match lower bits? */ + lower_bits ^= bp->lm; /* What bits are different? */ + lower_bits = ~lower_bits; /* Invert. */ + lower_bits |= bp->lk; /* What bits don't matter for matching? */ + lower_bits = ~lower_bits; /* Invert. */ + + if (lower_bits) + return 0; + + /* I always knew you'd be the one. */ + return 1; +} + +/* Given PHYS_ADDR, search memory controller banks for a match. */ +static struct bank_info *find_bank(unsigned long phys_addr) +{ + struct list_head *mctrl_head = &mctrl_list; + struct list_head *mctrl_entry = mctrl_head->next; + + for (;;) { + struct mctrl_info *mp = + list_entry(mctrl_entry, struct mctrl_info, list); + int bank_no; + + if (mctrl_entry == mctrl_head) + break; + mctrl_entry = mctrl_entry->next; + + for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) { + struct bank_info *bp; + + bp = &mp->logical_banks[bank_no]; + if (bank_match(bp, phys_addr)) + return bp; + } + } + + return NULL; +} + +/* This is the main purpose of this driver. */ +#define SYNDROME_MIN -1 +#define SYNDROME_MAX 144 +int chmc_getunumber(int syndrome_code, + unsigned long phys_addr, + char *buf, int buflen) +{ + struct bank_info *bp; + struct obp_mem_layout *prop; + int bank_in_controller, first_dimm; + + bp = find_bank(phys_addr); + if (bp == NULL || + syndrome_code < SYNDROME_MIN || + syndrome_code > SYNDROME_MAX) { + buf[0] = '?'; + buf[1] = '?'; + buf[2] = '?'; + buf[3] = '\0'; + return 0; + } + + prop = &bp->mp->layout_prop; + bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1); + first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1)); + first_dimm *= CHMCTRL_NDIMMS; + + if (syndrome_code != SYNDROME_MIN) { + struct obp_map *map; + int qword, where_in_line, where, map_index, map_offset; + unsigned int map_val; + + /* Yaay, single bit error so we can figure out + * the exact dimm. + */ + if (prop->symmetric) + map = &prop->map[0]; + else + map = &prop->map[1]; + + /* Covert syndrome code into the way the bits are + * positioned on the bus. + */ + if (syndrome_code < 144 - 16) + syndrome_code += 16; + else if (syndrome_code < 144) + syndrome_code -= (144 - 7); + else if (syndrome_code < (144 + 3)) + syndrome_code -= (144 + 3 - 4); + else + syndrome_code -= 144 + 3; + + /* All this magic has to do with how a cache line + * comes over the wire on Safari. A 64-bit line + * comes over in 4 quadword cycles, each of which + * transmit ECC/MTAG info as well as the actual + * data. 144 bits per quadword, 576 total. + */ +#define LINE_SIZE 64 +#define LINE_ADDR_MSK (LINE_SIZE - 1) +#define QW_PER_LINE 4 +#define QW_BYTES (LINE_SIZE / QW_PER_LINE) +#define QW_BITS 144 +#define LAST_BIT (576 - 1) + + qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES; + where_in_line = ((3 - qword) * QW_BITS) + syndrome_code; + where = (LAST_BIT - where_in_line); + map_index = where >> 2; + map_offset = where & 0x3; + map_val = map->dimm_map[map_index]; + map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1)); + + sprintf(buf, "%s, pin %3d", + prop->dimm_labels[first_dimm + map_val], + map->pin_map[where_in_line]); + } else { + int dimm; + + /* Multi-bit error, we just dump out all the + * dimm labels assosciated with this bank. + */ + for (dimm = 0; dimm < CHMCTRL_NDIMMS; dimm++) { + sprintf(buf, "%s ", + prop->dimm_labels[first_dimm + dimm]); + buf += strlen(buf); + } + } + return 0; +} + +/* Accessing the registers is slightly complicated. If you want + * to get at the memory controller which is on the same processor + * the code is executing, you must use special ASI load/store else + * you go through the global mapping. + */ +static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset) +{ + unsigned long ret; + + if (mp->portid == smp_processor_id()) { + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (offset), "i" (ASI_MCU_CTRL_REG)); + } else { + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (mp->regs + offset), + "i" (ASI_PHYS_BYPASS_EC_E)); + } + return ret; +} + +#if 0 /* currently unused */ +static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val) +{ + if (mp->portid == smp_processor_id()) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (val), + "r" (offset), "i" (ASI_MCU_CTRL_REG)); + } else { + __asm__ __volatile__("ldxa %0, [%1] %2" + : : "r" (val), + "r" (mp->regs + offset), + "i" (ASI_PHYS_BYPASS_EC_E)); + } +} +#endif + +static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val) +{ + struct bank_info *p = &mp->logical_banks[which_bank]; + + p->mp = mp; + p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank; + p->raw_reg = val; + p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT; + p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT; + p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT; + p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT; + p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT; + + p->base = (p->um); + p->base &= ~(p->uk); + p->base <<= PA_UPPER_BITS_SHIFT; + + switch(p->lk) { + case 0xf: + default: + p->interleave = 1; + break; + + case 0xe: + p->interleave = 2; + break; + + case 0xc: + p->interleave = 4; + break; + + case 0x8: + p->interleave = 8; + break; + + case 0x0: + p->interleave = 16; + break; + }; + + /* UK[10] is reserved, and UK[11] is not set for the SDRAM + * bank size definition. + */ + p->size = (((unsigned long)p->uk & + ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT; + p->size /= p->interleave; +} + +static void fetch_decode_regs(struct mctrl_info *mp) +{ + if (mp->layout_size == 0) + return; + + interpret_one_decode_reg(mp, 0, + read_mcreg(mp, CHMCTRL_DECODE1)); + interpret_one_decode_reg(mp, 1, + read_mcreg(mp, CHMCTRL_DECODE2)); + interpret_one_decode_reg(mp, 2, + read_mcreg(mp, CHMCTRL_DECODE3)); + interpret_one_decode_reg(mp, 3, + read_mcreg(mp, CHMCTRL_DECODE4)); +} + +static int init_one_mctrl(int node, int index) +{ + struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL); + int portid = prom_getintdefault(node, "portid", -1); + struct linux_prom64_registers p_reg_prop; + int t; + + if (!mp) + return -1; + memset(mp, 0, sizeof(*mp)); + if (portid == -1) + goto fail; + + mp->portid = portid; + mp->layout_size = prom_getproplen(node, "memory-layout"); + if (mp->layout_size < 0) + mp->layout_size = 0; + if (mp->layout_size > sizeof(mp->layout_prop)) + goto fail; + + if (mp->layout_size > 0) + prom_getproperty(node, "memory-layout", + (char *) &mp->layout_prop, + mp->layout_size); + + t = prom_getproperty(node, "reg", + (char *) &p_reg_prop, + sizeof(p_reg_prop)); + if (t < 0 || p_reg_prop.reg_size != 0x48) + goto fail; + + mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size); + if (mp->regs == NULL) + goto fail; + + if (mp->layout_size != 0UL) { + mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1); + mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2); + mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3); + mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4); + mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL); + } + + fetch_decode_regs(mp); + + mp->index = index; + + list_add(&mp->list, &mctrl_list); + + /* Report the device. */ + printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n", + mp->index, + mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE")); + + return 0; + +fail: + if (mp) { + if (mp->regs != NULL) + iounmap(mp->regs); + kfree(mp); + } + return -1; +} + +static int __init probe_for_string(char *name, int index) +{ + int node = prom_getchild(prom_root_node); + + while ((node = prom_searchsiblings(node, name)) != 0) { + int ret = init_one_mctrl(node, index); + + if (!ret) + index++; + + node = prom_getsibling(node); + if (!node) + break; + } + + return index; +} + +static int __init chmc_init(void) +{ + int index; + + /* This driver is only for cheetah platforms. */ + if (tlb_type != cheetah) + return -ENODEV; + + index = probe_for_string("memory-controller", 0); + index = probe_for_string("mc-us3", index); + + return 0; +} + +static void __exit chmc_cleanup(void) +{ + struct list_head *head = &mctrl_list; + struct list_head *tmp = head->next; + + for (;;) { + struct mctrl_info *p = + list_entry(tmp, struct mctrl_info, list); + if (tmp == head) + break; + tmp = tmp->next; + + list_del(&p->list); + iounmap(p->regs); + kfree(p); + } +} + +module_init(chmc_init); +module_exit(chmc_cleanup); diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S --- v2.4.3/linux/arch/sparc64/kernel/dtlb_prot.S Sun Nov 12 20:37:16 2000 +++ linux/arch/sparc64/kernel/dtlb_prot.S Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: dtlb_prot.S,v 1.21 2000/11/10 08:28:45 davem Exp $ +/* $Id: dtlb_prot.S,v 1.22 2001/04/11 23:40:32 davem Exp $ * dtlb_prot.S: DTLB protection trap strategy. * This is included directly into the trap table. * @@ -43,7 +43,7 @@ nop nop -/* PROT ** ICACHE line 3: Unused... */ +/* PROT ** ICACHE line 4: Unused... */ nop nop nop diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.4.3/linux/arch/sparc64/kernel/entry.S Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/entry.S Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.127 2001/03/23 07:56:30 davem Exp $ +/* $Id: entry.S,v 1.128 2001/03/28 10:56:34 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -19,6 +19,7 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/visasm.h> +#include <asm/estate.h> /* #define SYSCALL_TRACING */ @@ -788,6 +789,284 @@ call cee_log add %sp, STACK_BIAS + REGWIN_SZ, %o2 ba,a,pt %xcc, rtrap_clr_l6 + + /* Capture I/D/E-cache state into per-cpu error scoreboard. + * + * %g1: (TL>=0) ? 1 : 0 + * %g2: scratch + * %g3: scratch + * %g4: AFSR + * %g5: AFAR + * %g6: current thread ptr + * %g7: scratch + */ +#define CHEETAH_LOG_ERROR \ + /* Put "TL1" software bit into AFSR. */ \ + and %g1, 0x1, %g1; \ + sllx %g1, 63, %g2; \ + or %g4, %g2, %g4; \ + /* Get log entry pointer for this cpu at this trap level. */ \ + ldxa [%g0] ASI_SAFARI_CONFIG, %g2; \ + srlx %g2, 17, %g2; \ + and %g2, 0x3ff, %g2; \ + sllx %g2, 9, %g2; \ + sethi %hi(cheetah_error_log), %g3; \ + ldx [%g3 + %lo(cheetah_error_log)], %g3; \ + brz,pn %g3, 80f; \ + nop; \ + add %g3, %g2, %g3; \ + sllx %g1, 8, %g1; \ + add %g3, %g1, %g1; \ + /* %g1 holds pointer to the top of the logging scoreboard */ \ + ldx [%g1 + 0x0], %g7; \ + cmp %g7, -1; \ + bne,pn %xcc, 80f; \ + nop; \ + stx %g4, [%g1 + 0x0]; \ + stx %g5, [%g1 + 0x8]; \ + add %g1, 0x10, %g1; \ + /* %g1 now points to D-cache logging area */ \ + set 0x3ff8, %g2; /* DC_addr mask */ \ + and %g5, %g2, %g2; /* DC_addr bits of AFAR */ \ + srlx %g5, 12, %g3; \ + or %g3, 1, %g3; /* PHYS tag + valid */ \ +10: ldxa [%g2] ASI_DCACHE_TAG, %g7; \ + cmp %g3, %g7; /* TAG match? */ \ + bne,pt %xcc, 13f; \ + nop; \ + /* Yep, what we want, capture state. */ \ + stx %g2, [%g1 + 0x20]; \ + stx %g7, [%g1 + 0x28]; \ + /* A membar Sync is required before and after utag access. */ \ + membar #Sync; \ + ldxa [%g2] ASI_DCACHE_UTAG, %g7; \ + membar #Sync; \ + stx %g7, [%g1 + 0x30]; \ + ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7; \ + stx %g7, [%g1 + 0x38]; \ + clr %g3; \ +12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7; \ + stx %g7, [%g1]; \ + add %g3, (1 << 5), %g3; \ + cmp %g3, (4 << 5); \ + bl,pt %xcc, 12b; \ + add %g1, 0x8, %g1; \ + ba,pt %xcc, 20f; \ + add %g1, 0x20, %g1; \ +13: sethi %hi(1 << 14), %g7; \ + add %g2, %g7, %g2; \ + srlx %g2, 14, %g7; \ + cmp %g7, 4; \ + bl,pt %xcc, 10b; \ + nop; \ + add %g1, 0x40, %g1; \ +20: /* %g1 now points to I-cache logging area */ \ + set 0x1fe0, %g2; /* IC_addr mask */ \ + and %g5, %g2, %g2; /* IC_addr bits of AFAR */ \ + sllx %g2, 1, %g2; /* IC_addr[13:6]==VA[12:5] */ \ + srlx %g5, (13 - 8), %g3; /* Make PTAG */ \ + andn %g3, 0xff, %g3; /* Mask off undefined bits */ \ +21: ldxa [%g2] ASI_IC_TAG, %g7; \ + andn %g7, 0xff, %g7; \ + cmp %g3, %g7; \ + bne,pt %xcc, 23f; \ + nop; \ + /* Yep, what we want, capture state. */ \ + stx %g2, [%g1 + 0x40]; \ + stx %g7, [%g1 + 0x48]; \ + add %g2, (1 << 3), %g2; \ + ldxa [%g2] ASI_IC_TAG, %g7; \ + add %g2, (1 << 3), %g2; \ + stx %g7, [%g1 + 0x50]; \ + ldxa [%g2] ASI_IC_TAG, %g7; \ + add %g2, (1 << 3), %g2; \ + stx %g7, [%g1 + 0x60]; \ + ldxa [%g2] ASI_IC_TAG, %g7; \ + stx %g7, [%g1 + 0x68]; \ + sub %g2, (3 << 3), %g2; \ + ldxa [%g2] ASI_IC_STAG, %g7; \ + stx %g7, [%g1 + 0x58]; \ + clr %g3; \ + srlx %g2, 2, %g2; \ +22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7; \ + stx %g7, [%g1]; \ + add %g3, (1 << 3), %g3; \ + cmp %g3, (8 << 3); \ + bl,pt %xcc, 22b; \ + add %g1, 0x8, %g1; \ + ba,pt %xcc, 30f; \ + add %g1, 0x30, %g1; \ +23: sethi %hi(1 << 14), %g7; \ + add %g2, %g7, %g2; \ + srlx %g2, 14, %g7; \ + cmp %g7, 4; \ + bl,pt %xcc, 21b; \ + nop; \ + add %g1, 0x70, %g1; \ +30: /* %g1 now points to E-cache logging area */ \ + andn %g5, (32 - 1), %g2; /* E-cache subblock */ \ + stx %g2, [%g1 + 0x20]; \ + ldxa [%g2] ASI_EC_TAG_DATA, %g7; \ + stx %g7, [%g1 + 0x28]; \ + ldxa [%g2] ASI_EC_R, %g0; \ + clr %g3; \ +31: ldxa [%g3] ASI_EC_DATA, %g7; \ + stx %g7, [%g1 + %g3]; \ + add %g3, 0x8, %g3; \ + cmp %g3, 0x20; \ + bl,pt %xcc, 31b; \ + nop; \ +80: /* DONE */ + + /* These get patched into the trap table at boot time + * once we know we have a cheetah processor. + */ + .globl cheetah_fecc_trap_vector, cheetah_fecc_trap_vector_tl1 +cheetah_fecc_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_DC | DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_fast_ecc), %g2 + jmpl %g2 + %lo(cheetah_fast_ecc), %g0 + mov 0, %g1 +cheetah_fecc_trap_vector_tl1: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_DC | DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_fast_ecc), %g2 + jmpl %g2 + %lo(cheetah_fast_ecc), %g0 + mov 1, %g1 + .globl cheetah_cee_trap_vector, cheetah_cee_trap_vector_tl1 +cheetah_cee_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_cee), %g2 + jmpl %g2 + %lo(cheetah_cee), %g0 + mov 0, %g1 +cheetah_cee_trap_vector_tl1: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_cee), %g2 + jmpl %g2 + %lo(cheetah_cee), %g0 + mov 1, %g1 + .globl cheetah_deferred_trap_vector, cheetah_deferred_trap_vector_tl1 +cheetah_deferred_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; + andn %g1, DCU_DC | DCU_IC, %g1; + stxa %g1, [%g0] ASI_DCU_CONTROL_REG; + membar #Sync; + sethi %hi(cheetah_deferred_trap), %g2 + jmpl %g2 + %lo(cheetah_deferred_trap), %g0 + mov 0, %g1 +cheetah_deferred_trap_vector_tl1: + membar #Sync; + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; + andn %g1, DCU_DC | DCU_IC, %g1; + stxa %g1, [%g0] ASI_DCU_CONTROL_REG; + membar #Sync; + sethi %hi(cheetah_deferred_trap), %g2 + jmpl %g2 + %lo(cheetah_deferred_trap), %g0 + mov 1, %g1 + + /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc + * in the trap table. That code has done a memory barrier + * and has disabled both the I-cache and D-cache in the DCU + * control register. The I-cache is disabled so that we may + * capture the corrupted cache line, and the D-cache is disabled + * because corrupt data may have been placed there and we don't + * want to reference it. + * + * %g1 is one if this trap occured at %tl >= 1. + * + * Next, we turn off error reporting so that we don't recurse. + */ + .globl cheetah_fast_ecc +cheetah_fast_ecc: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + CHEETAH_LOG_ERROR + + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o1 + mov %l5, %o2 + call cheetah_fecc_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap_clr_l6 + + /* Our caller has disabled I-cache and performed membar Sync. */ + .globl cheetah_cee +cheetah_cee: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + CHEETAH_LOG_ERROR + + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o1 + mov %l5, %o2 + call cheetah_cee_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap_clr_l6 + + /* Our caller has disabled I-cache+D-cache and performed membar Sync. */ + .globl cheetah_deferred_trap +cheetah_deferred_trap: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + CHEETAH_LOG_ERROR + + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o1 + mov %l5, %o2 + call cheetah_deferred_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rtrap_clr_l6 .globl __do_privact __do_privact: diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.4.3/linux/arch/sparc64/kernel/head.S Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/head.S Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.75 2001/03/22 09:54:26 davem Exp $ +/* $Id: head.S,v 1.77 2001/04/05 12:44:34 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -90,13 +90,25 @@ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 wr %g1, %asr18 - sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 - or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + sethi %uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + or %g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 sllx %g5, 32, %g5 or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - or %g5, %g3, %g5 stxa %g5, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + + mov TSB_EXTENSION_P, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU + membar #Sync + + mov TSB_EXTENSION_S, %g3 + stxa %g0, [%g3] ASI_DMMU + membar #Sync + + mov TSB_EXTENSION_N, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU membar #Sync wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.4.3/linux/arch/sparc64/kernel/ioctl32.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/ioctl32.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.110 2001/03/22 12:51:25 davem Exp $ +/* $Id: ioctl32.c,v 1.111 2001/03/27 07:28:43 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -527,6 +527,55 @@ return err; } +static inline int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data, ethcmd; + + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + + if (get_user(ethcmd, (u32 *)A(data))) { + err = -EFAULT; + goto out; + } + switch (ethcmd) { + case ETHTOOL_GDRVINFO: len = sizeof(struct ethtool_drvinfo); break; + case ETHTOOL_GSET: + case ETHTOOL_SSET: + default: len = sizeof(struct ethtool_cmd); break; + } + + if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { + err = -EFAULT; + goto out; + } + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + u32 data; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + len = copy_to_user((char *)A(data), ifr.ifr_data, len); + if (len) + err = -EFAULT; + } + +out: + free_page((unsigned long)ifr.ifr_data); + return err; +} + static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifreq ifr; @@ -548,23 +597,11 @@ case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: - case SIOCETHTOOL: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; - if(cmd == SIOCETHTOOL) { - u32 data; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - if(copy_from_user(ifr.ifr_data, - (char *)A(data), - sizeof(struct ethtool_cmd))) { - free_page((unsigned long)ifr.ifr_data); - return -EFAULT; - } - } break; default: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) @@ -594,14 +631,11 @@ case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: - case SIOCETHTOOL: { u32 data; int len; __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - if(cmd == SIOCETHTOOL) - len = sizeof(struct ethtool_cmd); if(cmd == SIOCGPPPVER) len = strlen((char *)ifr.ifr_data) + 1; else if(cmd == SIOCGPPPCSTATS) @@ -627,6 +661,14 @@ err = -EFAULT; break; } + } else { + switch (cmd) { + case SIOCGPPPSTATS: + case SIOCGPPPCSTATS: + case SIOCGPPPVER: + free_page((unsigned long)ifr.ifr_data); + break; + } } return err; } @@ -3705,7 +3747,7 @@ HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc) HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCETHTOOL, dev_ifsioc) +HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) HANDLE_IOCTL(SIOCADDRT, routing_ioctl) HANDLE_IOCTL(SIOCDELRT, routing_ioctl) /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.4.3/linux/arch/sparc64/kernel/pci.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/pci.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.23 2001/03/14 04:17:14 davem Exp $ +/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -73,6 +73,7 @@ spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED; volatile int pci_poke_in_progress; +volatile int pci_poke_cpu = -1; volatile int pci_poke_faulted; /* Probe for all PCI controllers in the system. */ diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h --- v2.4.3/linux/arch/sparc64/kernel/pci_impl.h Mon Mar 27 10:35:56 2000 +++ linux/arch/sparc64/kernel/pci_impl.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_impl.h,v 1.6 2000/03/25 05:18:11 davem Exp $ +/* $Id: pci_impl.h,v 1.7 2001/03/28 10:56:34 davem Exp $ * pci_impl.h: Helper definitions for PCI controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -41,6 +41,7 @@ /* Configuration space access. */ extern spinlock_t pci_poke_lock; extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_cpu; extern volatile int pci_poke_faulted; static __inline__ void pci_config_read8(u8 *addr, u8 *ret) @@ -49,6 +50,7 @@ u8 byte; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -58,6 +60,7 @@ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; if (!pci_poke_faulted) *ret = byte; spin_unlock_irqrestore(&pci_poke_lock, flags); @@ -69,6 +72,7 @@ u16 word; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -78,6 +82,7 @@ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; if (!pci_poke_faulted) *ret = word; spin_unlock_irqrestore(&pci_poke_lock, flags); @@ -89,6 +94,7 @@ u32 dword; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -98,6 +104,7 @@ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; if (!pci_poke_faulted) *ret = dword; spin_unlock_irqrestore(&pci_poke_lock, flags); @@ -108,6 +115,7 @@ unsigned long flags; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -117,6 +125,7 @@ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; spin_unlock_irqrestore(&pci_poke_lock, flags); } @@ -125,6 +134,7 @@ unsigned long flags; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -134,6 +144,7 @@ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; spin_unlock_irqrestore(&pci_poke_lock, flags); } @@ -142,6 +153,7 @@ unsigned long flags; spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" @@ -151,6 +163,7 @@ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) : "memory"); pci_poke_in_progress = 0; + pci_poke_cpu = -1; spin_unlock_irqrestore(&pci_poke_lock, flags); } diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.4.3/linux/arch/sparc64/kernel/process.c Mon Mar 26 11:01:17 2001 +++ linux/arch/sparc64/kernel/process.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.116 2001/03/24 09:36:01 davem Exp $ +/* $Id: process.c,v 1.117 2001/03/30 07:10:41 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c --- v2.4.3/linux/arch/sparc64/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/sparc64/kernel/semaphore.c Tue Apr 17 17:19:30 2001 @@ -1,4 +1,4 @@ -/* $Id: semaphore.c,v 1.5 2000/11/10 04:02:03 davem Exp $ +/* $Id: semaphore.c,v 1.6 2001/04/14 01:12:02 davem Exp $ * Generic semaphore code. Buyer beware. Do your own * specific changes in <asm/semaphore-helper.h> */ @@ -125,173 +125,4 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); -} - -/* rw mutexes - * Implemented by Jakub Jelinek (jakub@redhat.com) based on - * i386 implementation by Ben LaHaise (bcrl@redhat.com). - */ - -asm(" - .text - .align 32 - .globl __down_read_failed -__down_read_failed: - save %sp, -160, %sp - membar #StoreStore - brz,pt %g5, 3f - mov %g7, %l0 -1: call down_read_failed - mov %l0, %o0 -2: lduw [%l0], %l1 - sub %l1, 1, %l2 - cas [%l0], %l1, %l2 - - cmp %l1, %l2 - bne,pn %icc, 2b - membar #StoreStore - subcc %l1, 1, %g0 - bpos,pt %icc, 4f - nop - bcc,pn %icc, 1b - nop - -3: call down_read_failed_biased - mov %l0, %o0 -4: ret - restore - .previous -"); - -asm(" - .text - .align 32 - .globl __down_write_failed -__down_write_failed: - save %sp, -160, %sp - membar #StoreStore - tst %g5 - bge,pt %icc, 3f - mov %g7, %l0 -1: call down_write_failed - mov %l0, %o0 -2: lduw [%l0], %l1 - sethi %hi (" RW_LOCK_BIAS_STR "), %l3 - sub %l1, %l3, %l2 - cas [%l0], %l1, %l2 - - cmp %l1, %l2 - bne,pn %icc, 2b - membar #StoreStore - subcc %l1, %l3, %g0 - be,pt %icc, 4f - nop - bcc,pn %icc, 1b - nop - -3: call down_write_failed_biased - mov %l0, %o0 -4: ret - restore - .previous -"); - -void down_read_failed_biased(struct rw_semaphore *sem) -{ - DOWN_VAR - - add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ - - for (;;) { - if (test_and_clear_le_bit(0, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!test_le_bit(0, &sem->granted)) - schedule(); - } - - remove_wait_queue(&sem->wait, &wait); - tsk->state = TASK_RUNNING; -} - -void down_write_failed_biased(struct rw_semaphore *sem) -{ - DOWN_VAR - - add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ - - for (;;) { - if (test_and_clear_le_bit(1, &sem->granted)) - break; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!test_le_bit(1, &sem->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); -} - -/* Wait for the lock to become unbiased. Readers - * are non-exclusive. =) - */ -void down_read_failed(struct rw_semaphore *sem) -{ - DOWN_VAR - - __up_read(sem); /* this takes care of granting the lock */ - - 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. Since we're - * a writer, we'll make ourselves exclusive. - */ -void down_write_failed(struct rw_semaphore *sem) -{ - DOWN_VAR - - __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; -} - -void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) -{ - if (readers) { - if (test_and_set_le_bit(0, &sem->granted)) - BUG(); - wake_up(&sem->wait); - } else { - if (test_and_set_le_bit(1, &sem->granted)) - BUG(); - wake_up(&sem->write_bias_wait); - } } diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.4.3/linux/arch/sparc64/kernel/smp.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/smp.c Thu Apr 12 12:10:25 2001 @@ -415,9 +415,7 @@ /* Setup the dispatch data registers. */ __asm__ __volatile__("stxa %0, [%3] %6\n\t" - "membar #Sync\n\t" "stxa %1, [%4] %6\n\t" - "membar #Sync\n\t" "stxa %2, [%5] %6\n\t" "membar #Sync\n\t" : /* no outputs */ @@ -994,6 +992,8 @@ cycles_t cacheflush_time; +extern unsigned long cheetah_tune_scheduling(void); + static void __init smp_tune_scheduling (void) { unsigned long orig_flush_base, flush_base, flags, *p; @@ -1011,6 +1011,11 @@ * of moving a process from one cpu to another). */ printk("SMP: Calibrating ecache flush... "); + if (tlb_type == cheetah) { + cacheflush_time = cheetah_tune_scheduling(); + goto report; + } + ecache_size = prom_getintdefault(linux_cpus[0].prom_node, "ecache-size", (512 * 1024)); if (ecache_size > (4 * 1024 * 1024)) @@ -1063,7 +1068,7 @@ cacheflush_time = ((ecache_size << 2) + (ecache_size << 1)); } - +report: printk("Using heuristic of %d cycles.\n", (int) cacheflush_time); } diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.4.3/linux/arch/sparc64/kernel/sparc64_ksyms.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.102 2001/03/24 09:36:01 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.105 2001/04/14 01:12:02 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -149,6 +149,8 @@ EXPORT_SYMBOL(_do_write_unlock); #endif +EXPORT_SYMBOL(smp_call_function); + #endif /* semaphores */ @@ -157,21 +159,16 @@ EXPORT_SYMBOL(__down_trylock); EXPORT_SYMBOL(__up); -/* rw semaphores */ -EXPORT_SYMBOL_NOVERS(__down_read_failed); -EXPORT_SYMBOL_NOVERS(__down_write_failed); -EXPORT_SYMBOL_NOVERS(__rwsem_wake); - /* Atomic counter implementation. */ EXPORT_SYMBOL(__atomic_add); EXPORT_SYMBOL(__atomic_sub); /* Atomic bit operations. */ -EXPORT_SYMBOL(__test_and_set_bit); -EXPORT_SYMBOL(__test_and_clear_bit); -EXPORT_SYMBOL(__test_and_change_bit); -EXPORT_SYMBOL(__test_and_set_le_bit); -EXPORT_SYMBOL(__test_and_clear_le_bit); +EXPORT_SYMBOL(___test_and_set_bit); +EXPORT_SYMBOL(___test_and_clear_bit); +EXPORT_SYMBOL(___test_and_change_bit); +EXPORT_SYMBOL(___test_and_set_le_bit); +EXPORT_SYMBOL(___test_and_clear_le_bit); EXPORT_SYMBOL(ivector_table); EXPORT_SYMBOL(enable_irq); @@ -180,7 +177,7 @@ EXPORT_SYMBOL(__flushw_user); EXPORT_SYMBOL(tlb_type); - +EXPORT_SYMBOL(get_fb_unmapped_area); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(__flush_dcache_page); diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/starfire.c linux/arch/sparc64/kernel/starfire.c --- v2.4.3/linux/arch/sparc64/kernel/starfire.c Sun Feb 18 19:49:54 2001 +++ linux/arch/sparc64/kernel/starfire.c Fri Apr 13 20:26:07 2001 @@ -2,7 +2,7 @@ * starfire.c: Starfire/E10000 support. * * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #include <linux/kernel.h> diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.4.3/linux/arch/sparc64/kernel/sys_sparc.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/sys_sparc.c Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.50 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sparc.c,v 1.52 2001/04/14 01:12:02 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -42,19 +42,28 @@ #define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) -unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct vm_area_struct * vmm; unsigned long task_size = TASK_SIZE; + if (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) + return -EINVAL; + return addr; + } + if (current->thread.flags & SPARC_FLAG_32BIT) task_size = 0xf0000000UL; if (len > task_size || len > -PAGE_OFFSET) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -68,15 +77,58 @@ vmm = find_vma(current->mm, PAGE_OFFSET); } if (task_size < addr) - return 0; + return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; - if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); } } +/* Try to align mapping such that we align it as much as possible. */ +unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) +{ + unsigned long align_goal, addr = -ENOMEM; + + if (flags & MAP_FIXED) { + /* Ok, don't mess with it. */ + return get_unmapped_area(NULL, addr, len, pgoff, flags); + } + flags &= ~MAP_SHARED; + + align_goal = PAGE_SIZE; + if (len >= (4UL * 1024 * 1024)) + align_goal = (4UL * 1024 * 1024); + else if (len >= (512UL * 1024)) + align_goal = (512UL * 1024); + else if (len >= (64UL * 1024)) + align_goal = (64UL * 1024); + + do { + addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); + if (!(addr & ~PAGE_MASK)) { + addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); + break; + } + + if (align_goal == (4UL * 1024 * 1024)) + align_goal = (512UL * 1024); + else if (align_goal == (512UL * 1024)) + align_goal = (64UL * 1024); + else + align_goal = PAGE_SIZE; + } while ((addr & ~PAGE_MASK) && align_goal > PAGE_SIZE); + + /* Mapping is smaller than 64K or larger areas could not + * be obtained. + */ + if (addr & ~PAGE_MASK) + addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags); + + return addr; +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) @@ -240,15 +292,10 @@ goto out_putf; } - if (flags & MAP_SHARED) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; - down_write(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); up_write(¤t->mm->mmap_sem); - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - out_putf: if (file) fput(file); @@ -286,25 +333,36 @@ if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) goto out; down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); - if (vma && (vma->vm_flags & VM_SHARED)) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (new_addr < PAGE_OFFSET && new_addr + new_len > -PAGE_OFFSET) goto out_sem; } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { + unsigned long map_flags = 0; + struct file *file = NULL; + ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area(addr, new_len); - if (!new_addr) + + vma = find_vma(current->mm, addr); + if (vma) { + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + file = vma->vm_file; + } + + /* MREMAP_FIXED checked above. */ + new_addr = get_unmapped_area(file, addr, new_len, + vma ? vma->vm_pgoff : 0, + map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up_write(¤t->mm->mmap_sem); out: return ret; diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.4.3/linux/arch/sparc64/kernel/sys_sparc32.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/sys_sparc32.c Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.174 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sparc32.c,v 1.176 2001/04/14 01:12:02 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -4134,24 +4134,35 @@ if (addr > 0xf0000000UL - old_len) goto out; down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); - if (vma && (vma->vm_flags & VM_SHARED)) - current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (new_addr > 0xf0000000UL - new_len) goto out_sem; } else if (addr > 0xf0000000UL - new_len) { + unsigned long map_flags = 0; + struct file *file = NULL; + ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area(addr, new_len); - if (!new_addr) + + vma = find_vma(current->mm, addr); + if (vma) { + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + file = vma->vm_file; + } + + /* MREMAP_FIXED checked above. */ + new_addr = get_unmapped_area(file, addr, new_len, + vma ? vma->vm_pgoff : 0, + map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: - current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up_write(¤t->mm->mmap_sem); out: return ret; diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S --- v2.4.3/linux/arch/sparc64/kernel/trampoline.S Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/trampoline.S Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.19 2001/03/22 09:54:26 davem Exp $ +/* $Id: trampoline.S,v 1.21 2001/04/05 12:44:34 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -44,14 +44,26 @@ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 wr %g1, %asr18 - sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 - or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + sethi %uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + or %g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 sllx %g5, 32, %g5 or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 - ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 - or %g5, %g3, %g5 stxa %g5, [%g0] ASI_DCU_CONTROL_REG membar #Sync + + mov TSB_EXTENSION_P, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU + membar #Sync + + mov TSB_EXTENSION_S, %g3 + stxa %g0, [%g3] ASI_DMMU + membar #Sync + + mov TSB_EXTENSION_N, %g3 + stxa %g0, [%g3] ASI_DMMU + stxa %g0, [%g3] ASI_IMMU + membar #Sync /* Disable STICK_INT interrupts. */ sethi %hi(0x80000000), %g5 diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.4.3/linux/arch/sparc64/kernel/traps.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/traps.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.73 2001/03/22 07:26:03 davem Exp $ +/* $Id: traps.c,v 1.76 2001/04/03 13:46:31 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,7 @@ #include <linux/signal.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/mm.h> #include <asm/delay.h> #include <asm/system.h> @@ -27,231 +28,13 @@ #include <asm/fpumacro.h> #include <asm/lsu.h> #include <asm/dcu.h> +#include <asm/estate.h> +#include <asm/chafsr.h> #include <asm/psrcompat.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> #endif -/* #define SYSCALL_TRACING */ -/* #define VERBOSE_SYSCALL_TRACING */ -/* #define DEBUG_FPU */ - -#ifdef SYSCALL_TRACING -#ifdef VERBOSE_SYSCALL_TRACING -struct sdesc { - int scall_num; - char *name; - int num_args; - char arg_is_string[6]; -} sdesc_entries[] = { - { 0, "setup", 0, }, - { 1, "exit", 1, { 0, } }, - { 2, "fork", 0, }, - { 3, "read", 3, { 0, 0, 0, } }, - { 4, "write", 3, { 0, 0, 0, } }, - { 5, "open", 3, { 1, 0, 0, } }, - { 6, "close", 1, { 0, } }, - { 7, "wait4", 4, { 0, 0, 0, 0, } }, - { 8, "creat", 2, { 1, 0, } }, - { 9, "link", 2, { 1, 1, } }, - { 10, "unlink", 1, { 1, } }, - { 11, "execv", 2, { 1, 0, } }, - { 12, "chdir", 1, { 1, } }, - { 15, "chmod", 2, { 1, 0, } }, - { 16, "chown", 3, { 1, 0, 0, } }, - { 17, "brk", 1, { 0, } }, - { 19, "lseek", 3, { 0, 0, 0, } }, - { 27, "alarm", 1, { 0, } }, - { 29, "pause", 0, }, - { 33, "access", 2, { 1, 0, } }, - { 36, "sync", 0, }, - { 37, "kill", 2, { 0, 0, } }, - { 38, "stat", 2, { 1, 0, } }, - { 40, "lstat", 2, { 1, 0, } }, - { 41, "dup", 1, { 0, } }, - { 42, "pipd", 0, }, - { 54, "ioctl", 3, { 0, 0, 0, } }, - { 57, "symlink", 2, { 1, 1, } }, - { 58, "readlink", 3, { 1, 0, 0, } }, - { 59, "execve", 3, { 1, 0, 0, } }, - { 60, "umask", 1, { 0, } }, - { 62, "fstat", 2, { 0, 0, } }, - { 64, "getpagesize", 0, }, - { 71, "mmap", 6, { 0, 0, 0, 0, 0, 0, } }, - { 73, "munmap", 2, { 0, 0, } }, - { 74, "mprotect", 3, { 0, 0, 0, } }, - { 83, "setitimer", 3, { 0, 0, 0, } }, - { 90, "dup2", 2, { 0, 0, } }, - { 92, "fcntl", 3, { 0, 0, 0, } }, - { 93, "select", 5, { 0, 0, 0, 0, 0, } }, - { 97, "socket", 3, { 0, 0, 0, } }, - { 98, "connect", 3, { 0, 0, 0, } }, - { 99, "accept", 3, { 0, 0, 0, } }, - { 101, "send", 4, { 0, 0, 0, 0, } }, - { 102, "recv", 4, { 0, 0, 0, 0, } }, - { 104, "bind", 3, { 0, 0, 0, } }, - { 105, "setsockopt", 5, { 0, 0, 0, 0, 0, } }, - { 106, "listen", 2, { 0, 0, } }, - { 120, "readv", 3, { 0, 0, 0, } }, - { 121, "writev", 3, { 0, 0, 0, } }, - { 123, "fchown", 3, { 0, 0, 0, } }, - { 124, "fchmod", 2, { 0, 0, } }, - { 128, "rename", 2, { 1, 1, } }, - { 129, "truncate", 2, { 1, 0, } }, - { 130, "ftruncate", 2, { 0, 0, } }, - { 131, "flock", 2, { 0, 0, } }, - { 136, "mkdir", 2, { 1, 0, } }, - { 137, "rmdir", 1, { 1, } }, - { 146, "killpg", 1, { 0, } }, - { 157, "statfs", 2, { 1, 0, } }, - { 158, "fstatfs", 2, { 0, 0, } }, - { 159, "umount", 1, { 1, } }, - { 167, "mount", 5, { 1, 1, 1, 0, 0, } }, - { 174, "getdents", 3, { 0, 0, 0, } }, - { 176, "fchdir", 2, { 0, 0, } }, - { 198, "sigaction", 3, { 0, 0, 0, } }, - { 201, "sigsuspend", 1, { 0, } }, - { 206, "socketcall", 2, { 0, 0, } }, - { 216, "sigreturn", 0, }, - { 230, "newselect", 5, { 0, 0, 0, 0, 0, } }, - { 236, "llseek", 5, { 0, 0, 0, 0, 0, } }, - { 251, "sysctl", 1, { 0, } }, -}; -#define NUM_SDESC_ENTRIES (sizeof(sdesc_entries) / sizeof(sdesc_entries[0])) -#endif - -#ifdef VERBOSE_SYSCALL_TRACING -static char scall_strbuf[512]; -#endif - -void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) -{ -#ifdef VERBOSE_SYSCALL_TRACING - struct sdesc *sdp; - int i; -#endif - -#if 0 - if (!current->pid) return; -#endif - printk("SYS[%s:%d]: PC(%016lx) <%3d> ", - current->comm, current->pid, regs->tpc, (int)g1); -#ifdef VERBOSE_SYSCALL_TRACING - sdp = NULL; - for(i = 0; i < NUM_SDESC_ENTRIES; i++) - if(sdesc_entries[i].scall_num == g1) { - sdp = &sdesc_entries[i]; - break; - } - if(sdp) { - printk("%s(", sdp->name); - for(i = 0; i < sdp->num_args; i++) { - if(i) - printk(","); - if(!sdp->arg_is_string[i]) { - if (current->thread.flags & SPARC_FLAG_32BIT) - printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); - else - printk("%016lx", regs->u_regs[UREG_I0 + i]); - } else { - if (current->thread.flags & SPARC_FLAG_32BIT) - strncpy_from_user(scall_strbuf, - (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff), - 512); - else - strncpy_from_user(scall_strbuf, - (char *)regs->u_regs[UREG_I0 + i], - 512); - printk("%s", scall_strbuf); - } - } - printk(") "); - } -#endif -} - -unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) -{ -#if 0 - if (current->pid) -#endif - printk("ret[%016lx]\n", retval); - return retval; -} -#endif /* SYSCALL_TRACING */ - -#if 1 -void rtrap_check(struct pt_regs *regs) -{ - register unsigned long pgd_phys asm("o1"); - register unsigned long pgd_cache asm("o2"); - register unsigned long g1_or_g3 asm("o3"); - register unsigned long g2 asm("o4"); - unsigned long ctx; - -#if 0 - do { - unsigned long test; - __asm__ __volatile__("rdpr %%pstate, %0" - : "=r" (test)); - if((test & PSTATE_MG) != 0 || - (test & PSTATE_IE) == 0) { - printk("rtrap_check: Bogus pstate[%016lx]\n", test); - return; - } - } while(0); -#endif - - __asm__ __volatile__(" - rdpr %%pstate, %%o5 - wrpr %%o5, %4, %%pstate - or %%g1, %%g3, %2 - mov %%g2, %3 - mov %%g7, %0 - mov %5, %1 - ldxa [%1] %6, %1 - wrpr %%o5, 0x0, %%pstate" - : "=r" (pgd_phys), "=r" (pgd_cache), - "=r" (g1_or_g3), "=r" (g2) - : "i" (PSTATE_IE | PSTATE_MG), "i" (TSB_REG), - "i" (ASI_DMMU) - : "o5"); - - ctx = spitfire_get_secondary_context(); - - if((pgd_phys != __pa(current->mm->pgd)) || - ((pgd_cache != 0) && - (pgd_cache != pgd_val(current->mm->pgd[0])<<11UL)) || - (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) || -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) -#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) - (g2 != (KERN_HIGHBITS | KERN_LOWBITS)) || -#undef KERN_HIGHBITS -#undef KERN_LOWBITS - ((ctx != (current->mm->context & 0x3ff)) || - (ctx == 0) || - (CTX_HWBITS(current->mm->context) != ctx))) { - printk("SHIT[%s:%d]: " - "(PP[%016lx] CACH[%016lx] CTX[%lx] g1g3[%016lx] g2[%016lx]) ", - current->comm, current->pid, - pgd_phys, pgd_cache, ctx, g1_or_g3, g2); - printk("SHIT[%s:%d]: " - "[PP[%016lx] CACH[%016lx] CTX[%lx]] PC[%016lx:%016lx]\n", - current->comm, current->pid, - __pa(current->mm->pgd), - pgd_val(current->mm->pgd[0]), - current->mm->context & 0x3ff, - regs->tpc, regs->tnpc); - show_regs(regs); -#if 1 - __sti(); - while(1) - barrier(); -#endif - } -} -#endif - void bad_trap (struct pt_regs *regs, long lvl) { siginfo_t info; @@ -290,10 +73,8 @@ siginfo_t info; if (regs->tstate & TSTATE_PRIV) { -#if 1 - printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n", + printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", sfsr, sfar); -#endif die_if_kernel("Iax", regs); } if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { @@ -331,16 +112,11 @@ return; } /* Shit... */ -#if 1 - printk("data_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n", + printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", sfsr, sfar); -#endif die_if_kernel("Dax", regs); } -#if 0 - else - rtrap_check(regs); -#endif + info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = SEGV_MAPERR; @@ -352,6 +128,7 @@ #ifdef CONFIG_PCI /* This is really pathetic... */ extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_cpu; extern volatile int pci_poke_faulted; #endif @@ -405,7 +182,7 @@ void do_dae(struct pt_regs *regs) { #ifdef CONFIG_PCI - if (pci_poke_in_progress) { + if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { clean_and_reenable_l1_caches(); pci_poke_faulted = 1; @@ -539,6 +316,986 @@ } } +/* Cheetah error trap handling. */ +static unsigned long ecache_flush_physbase; +static unsigned long ecache_flush_linesize; +static unsigned long ecache_flush_size; + +/* WARNING: The error trap handlers in assembly know the precise + * layout of the following structure. + * + * C-level handlers below use this information to log the error + * and then determine how to recover (if possible). + */ +struct cheetah_err_info { +/*0x00*/u64 afsr; +/*0x08*/u64 afar; + + /* D-cache state */ +/*0x10*/u64 dcache_data[4]; /* The actual data */ +/*0x30*/u64 dcache_index; /* D-cache index */ +/*0x38*/u64 dcache_tag; /* D-cache tag/valid */ +/*0x40*/u64 dcache_utag; /* D-cache microtag */ +/*0x48*/u64 dcache_stag; /* D-cache snooptag */ + + /* I-cache state */ +/*0x50*/u64 icache_data[8]; /* The actual insns + predecode */ +/*0x90*/u64 icache_index; /* I-cache index */ +/*0x98*/u64 icache_tag; /* I-cache phys tag */ +/*0xa0*/u64 icache_utag; /* I-cache microtag */ +/*0xa8*/u64 icache_stag; /* I-cache snooptag */ +/*0xb0*/u64 icache_upper; /* I-cache upper-tag */ +/*0xb8*/u64 icache_lower; /* I-cache lower-tag */ + + /* E-cache state */ +/*0xc0*/u64 ecache_data[4]; /* 32 bytes from staging registers */ +/*0xe0*/u64 ecache_index; /* E-cache index */ +/*0xe8*/u64 ecache_tag; /* E-cache tag/state */ + +/*0xf0*/u64 __pad[32 - 30]; +}; +#define CHAFSR_INVALID ((u64)-1L) + +/* This is allocated at boot time based upon the largest hardware + * cpu ID in the system. We allocate two entries per cpu, one for + * TL==0 logging and one for TL >= 1 logging. + */ +struct cheetah_err_info *cheetah_error_log; + +static __inline__ struct cheetah_err_info *cheetah_get_error_log(unsigned long afsr) +{ + struct cheetah_err_info *p; + int cpu = smp_processor_id(); + + if (!cheetah_error_log) + return NULL; + + p = cheetah_error_log + (cpu * 2); + if ((afsr & CHAFSR_TL1) != 0UL) + p++; + + return p; +} + +extern unsigned int tl0_fecc[], tl1_fecc[]; +extern unsigned int tl0_cee[], tl1_cee[]; +extern unsigned int tl0_iae[], tl1_iae[]; +extern unsigned int tl0_dae[], tl1_dae[]; +extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[]; +extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[]; +extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[]; + +void cheetah_ecache_flush_init(void) +{ + unsigned long largest_size, smallest_linesize, order; + char type[16]; + int node, highest_cpu, i; + + /* Scan all cpu device tree nodes, note two values: + * 1) largest E-cache size + * 2) smallest E-cache line size + */ + largest_size = 0UL; + smallest_linesize = ~0UL; + node = prom_getchild(prom_root_node); + while ((node = prom_getsibling(node)) != 0) { + prom_getstring(node, "device_type", type, sizeof(type)); + if (!strcmp(type, "cpu")) { + unsigned long val; + + val = prom_getintdefault(node, "ecache-size", + (2 * 1024 * 1024)); + if (val > largest_size) + largest_size = val; + val = prom_getintdefault(node, "ecache-line-size", 64); + if (val < smallest_linesize) + smallest_linesize = val; + } + } + if (largest_size == 0UL || smallest_linesize == ~0UL) { + prom_printf("cheetah_ecache_flush_init: Cannot probe cpu E-cache " + "parameters.\n"); + prom_halt(); + } + + ecache_flush_size = (2 * largest_size); + ecache_flush_linesize = smallest_linesize; + + /* Discover a physically contiguous chunk of physical + * memory in 'sp_banks' of size ecache_flush_size calculated + * above. Store the physical base of this area at + * ecache_flush_physbase. + */ + for (node = 0; ; node++) { + if (sp_banks[node].num_bytes == 0) + break; + if (sp_banks[node].num_bytes >= ecache_flush_size) { + ecache_flush_physbase = sp_banks[node].base_addr; + break; + } + } + + /* Note: Zero would be a valid value of ecache_flush_physbase so + * don't use that as the success test. :-) + */ + if (sp_banks[node].num_bytes == 0) { + prom_printf("cheetah_ecache_flush_init: Cannot find %d byte " + "contiguous physical memory.\n", ecache_flush_size); + prom_halt(); + } + + /* Now allocate error trap reporting scoreboard. */ + highest_cpu = 0; +#ifdef CONFIG_SMP + for (i = 0; i < NR_CPUS; i++) { + if ((1UL << i) & cpu_present_map) + highest_cpu = i; + } +#endif + highest_cpu++; + node = highest_cpu * (2 * sizeof(struct cheetah_err_info)); + for (order = 0; order < MAX_ORDER; order++) { + if ((PAGE_SIZE << order) >= node) + break; + } + cheetah_error_log = (struct cheetah_err_info *) + __get_free_pages(GFP_KERNEL, order); + if (!cheetah_error_log) { + prom_printf("cheetah_ecache_flush_init: Failed to allocate " + "error logging scoreboard (%d bytes).\n", node); + prom_halt(); + } + memset(cheetah_error_log, 0, PAGE_SIZE << order); + + /* Mark all AFSRs as invalid so that the trap handler will + * log new new information there. + */ + for (i = 0; i < 2 * highest_cpu; i++) + cheetah_error_log[i].afsr = CHAFSR_INVALID; + + /* Now patch trap tables. */ + memcpy(tl0_fecc, cheetah_fecc_trap_vector, (8 * 4)); + memcpy(tl1_fecc, cheetah_fecc_trap_vector_tl1, (8 * 4)); + memcpy(tl0_cee, cheetah_cee_trap_vector, (8 * 4)); + memcpy(tl1_cee, cheetah_cee_trap_vector_tl1, (8 * 4)); + memcpy(tl0_iae, cheetah_deferred_trap_vector, (8 * 4)); + memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4)); + memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4)); + memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4)); + flushi(PAGE_OFFSET); +} + +static void cheetah_flush_ecache(void) +{ + unsigned long flush_base = ecache_flush_physbase; + unsigned long flush_linesize = ecache_flush_linesize; + unsigned long flush_size = ecache_flush_size; + + __asm__ __volatile__("1: subcc %0, %4, %0\n\t" + " bne,pt %%xcc, 1b\n\t" + " ldxa [%2 + %0] %3, %%g0\n\t" + : "=&r" (flush_size) + : "0" (flush_size), "r" (flush_base), + "i" (ASI_PHYS_USE_EC), "r" (flush_linesize)); +} + +static void cheetah_flush_ecache_line(unsigned long physaddr) +{ + unsigned long alias; + + physaddr &= ~(8UL - 1UL); + physaddr = (ecache_flush_physbase + + (physaddr & ((ecache_flush_size>>1UL) - 1UL))); + alias = physaddr + (ecache_flush_size >> 1UL); + __asm__ __volatile__("ldxa [%0] %2, %%g0\n\t" + "ldxa [%1] %2, %%g0\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (physaddr), "r" (alias), + "i" (ASI_PHYS_USE_EC)); +} + +#ifdef CONFIG_SMP +unsigned long cheetah_tune_scheduling(void) +{ + unsigned long tick1, tick2, raw; + + __asm__ __volatile__("rd %%tick, %0" : "=r" (tick1)); + cheetah_flush_ecache(); + __asm__ __volatile__("rd %%tick, %0" : "=r" (tick2)); + + raw = (tick2 - tick1); + + return (raw - (raw >> 2)); +} +#endif + +/* Unfortunately, the diagnostic access to the I-cache tags we need to + * use to clear the thing interferes with I-cache coherency transactions. + * + * So we must only flush the I-cache when it is disabled. + */ +static void cheetah_flush_icache(void) +{ + unsigned long dcu_save, i; + + /* Save current DCU, disable I-cache. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" + "or %0, %2, %%g1\n\t" + "stxa %%g1, [%%g0] %1\n\t" + "membar #Sync" + : "=r" (dcu_save) + : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC) + : "g1"); + + /* Clear the valid bits in all the tags. */ + for (i = 0; i < (1 << 16); i += (1 << 5)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (i | (2 << 3)), "i" (ASI_IC_TAG)); + } + + /* Restore DCU register */ + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (dcu_save), "i" (ASI_DCU_CONTROL_REG)); +} + +static void cheetah_flush_dcache(void) +{ + unsigned long i; + + for (i = 0; i < (1 << 16); i += (1 << 5)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (i), "i" (ASI_DCACHE_TAG)); + } +} + +/* Conversion tables used to frob Cheetah AFSR syndrome values into + * something palatable to the memory controller driver get_unumber + * routine. + */ +#define MT0 137 +#define MT1 138 +#define MT2 139 +#define NONE 254 +#define MTC0 140 +#define MTC1 141 +#define MTC2 142 +#define MTC3 143 +#define C0 128 +#define C1 129 +#define C2 130 +#define C3 131 +#define C4 132 +#define C5 133 +#define C6 134 +#define C7 135 +#define C8 136 +#define M2 144 +#define M3 145 +#define M4 146 +#define M 147 +static unsigned char cheetah_ecc_syntab[] = { +/*00*/NONE, C0, C1, M2, C2, M2, M3, 47, C3, M2, M2, 53, M2, 41, 29, M, +/*01*/C4, M, M, 50, M2, 38, 25, M2, M2, 33, 24, M2, 11, M, M2, 16, +/*02*/C5, M, M, 46, M2, 37, 19, M2, M, 31, 32, M, 7, M2, M2, 10, +/*03*/M2, 40, 13, M2, 59, M, M2, 66, M, M2, M2, 0, M2, 67, 71, M, +/*04*/C6, M, M, 43, M, 36, 18, M, M2, 49, 15, M, 63, M2, M2, 6, +/*05*/M2, 44, 28, M2, M, M2, M2, 52, 68, M2, M2, 62, M2, M3, M3, M4, +/*06*/M2, 26, 106, M2, 64, M, M2, 2, 120, M, M2, M3, M, M3, M3, M4, +/*07*/116, M2, M2, M3, M2, M3, M, M4, M2, 58, 54, M2, M, M4, M4, M3, +/*08*/C7, M2, M, 42, M, 35, 17, M2, M, 45, 14, M2, 21, M2, M2, 5, +/*09*/M, 27, M, M, 99, M, M, 3, 114, M2, M2, 20, M2, M3, M3, M, +/*0a*/M2, 23, 113, M2, 112, M2, M, 51, 95, M, M2, M3, M2, M3, M3, M2, +/*0b*/103, M, M2, M3, M2, M3, M3, M4, M2, 48, M, M, 73, M2, M, M3, +/*0c*/M2, 22, 110, M2, 109, M2, M, 9, 108, M2, M, M3, M2, M3, M3, M, +/*0d*/102, M2, M, M, M2, M3, M3, M, M2, M3, M3, M2, M, M4, M, M3, +/*0e*/98, M, M2, M3, M2, M, M3, M4, M2, M3, M3, M4, M3, M, M, M, +/*0f*/M2, M3, M3, M, M3, M, M, M, 56, M4, M, M3, M4, M, M, M, +/*10*/C8, M, M2, 39, M, 34, 105, M2, M, 30, 104, M, 101, M, M, 4, +/*11*/M, M, 100, M, 83, M, M2, 12, 87, M, M, 57, M2, M, M3, M, +/*12*/M2, 97, 82, M2, 78, M2, M2, 1, 96, M, M, M, M, M, M3, M2, +/*13*/94, M, M2, M3, M2, M, M3, M, M2, M, 79, M, 69, M, M4, M, +/*14*/M2, 93, 92, M, 91, M, M2, 8, 90, M2, M2, M, M, M, M, M4, +/*15*/89, M, M, M3, M2, M3, M3, M, M, M, M3, M2, M3, M2, M, M3, +/*16*/86, M, M2, M3, M2, M, M3, M, M2, M, M3, M, M3, M, M, M3, +/*17*/M, M, M3, M2, M3, M2, M4, M, 60, M, M2, M3, M4, M, M, M2, +/*18*/M2, 88, 85, M2, 84, M, M2, 55, 81, M2, M2, M3, M2, M3, M3, M4, +/*19*/77, M, M, M, M2, M3, M, M, M2, M3, M3, M4, M3, M2, M, M, +/*1a*/74, M, M2, M3, M, M, M3, M, M, M, M3, M, M3, M, M4, M3, +/*1b*/M2, 70, 107, M4, 65, M2, M2, M, 127, M, M, M, M2, M3, M3, M, +/*1c*/80, M2, M2, 72, M, 119, 118, M, M2, 126, 76, M, 125, M, M4, M3, +/*1d*/M2, 115, 124, M, 75, M, M, M3, 61, M, M4, M, M4, M, M, M, +/*1e*/M, 123, 122, M4, 121, M4, M, M3, 117, M2, M2, M3, M4, M3, M, M, +/*1f*/111, M, M, M, M4, M3, M3, M, M, M, M3, M, M3, M2, M, M +}; +static unsigned char cheetah_mtag_syntab[] = { + NONE, MTC0, + MTC1, NONE, + MTC2, NONE, + NONE, MT0, + MTC3, NONE, + NONE, MT1, + NONE, MT2, + NONE, NONE +}; + +/* This table is ordered in priority of errors and matches the + * AFAR overwrite policy as well. + */ +static struct { + unsigned long mask; + char *name; +} cheetah_error_table[] = { + { CHAFSR_PERR, "System interface protocol error" }, + { CHAFSR_IERR, "Internal processor error" }, + { CHAFSR_ISAP, "System request parity error on incoming addresss" }, + { CHAFSR_UCU, "Uncorrectable E-cache ECC error for ifetch/data" }, + { CHAFSR_UCC, "SW Correctable E-cache ECC error for ifetch/data" }, + { CHAFSR_UE, "Uncorrectable system bus data ECC error for read" }, + { CHAFSR_EDU, "Uncorrectable E-cache ECC error for stmerge/blkld" }, + { CHAFSR_EMU, "Uncorrectable system bus MTAG error" }, + { CHAFSR_WDU, "Uncorrectable E-cache ECC error for writeback" }, + { CHAFSR_CPU, "Uncorrectable ECC error for copyout" }, + { CHAFSR_CE, "HW corrected system bus data ECC error for read" }, + { CHAFSR_EDC, "HW corrected E-cache ECC error for stmerge/blkld" }, + { CHAFSR_EMC, "HW corrected system bus MTAG ECC error" }, + { CHAFSR_WDC, "HW corrected E-cache ECC error for writeback" }, + { CHAFSR_CPC, "HW corrected ECC error for copyout" }, + { CHAFSR_TO, "Unmapped error from system bus" }, + { CHAFSR_BERR, "Bus error response from system bus" }, + /* These two do not update the AFAR. */ + { CHAFSR_IVC, "HW corrected system bus data ECC error for ivec read" }, + { CHAFSR_IVU, "Uncorrectable system bus data ECC error for ivec read" }, + { 0, NULL } +}; + +/* Return the highest priority error conditon mentioned. */ +static __inline__ unsigned long cheetah_get_hipri(unsigned long afsr) +{ + unsigned long tmp = 0; + int i; + + for (i = 0; cheetah_error_table[i].mask; i++) { + if ((tmp = (afsr & cheetah_error_table[i].mask)) != 0UL) + return tmp; + } + return tmp; +} + +static char *cheetah_get_string(unsigned long bit) +{ + int i; + + for (i = 0; cheetah_error_table[i].mask; i++) { + if ((bit & cheetah_error_table[i].mask) != 0UL) + return cheetah_error_table[i].name; + } + return "???"; +} + +extern int chmc_getunumber(int, unsigned long, char *, int); + +static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info, + unsigned long afsr, unsigned long afar, int recoverable) +{ + unsigned long hipri; + char unum[256]; + + printk("%s" "ERROR(%d): Cheetah error trap taken afsr[%016lx] afar[%016lx] TL1(%d)\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + afsr, afar, + (afsr & CHAFSR_TL1) ? 1 : 0); + printk("%s" "ERROR(%d): TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + regs->tpc, regs->tnpc, regs->tstate); + printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT, + (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT, + (afsr & CHAFSR_ME) ? ", Multiple Errors" : "", + (afsr & CHAFSR_PRIV) ? ", Privileged" : ""); + hipri = cheetah_get_hipri(afsr); + printk("%s" "ERROR(%d): Highest priority error (%016lx) \"%s\"\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + hipri, cheetah_get_string(hipri)); + + /* Try to get unumber if relevant. */ +#define ESYND_ERRORS (CHAFSR_IVC | CHAFSR_IVU | \ + CHAFSR_CPC | CHAFSR_CPU | \ + CHAFSR_UE | CHAFSR_CE | \ + CHAFSR_EDC | CHAFSR_EDU | \ + CHAFSR_UCC | CHAFSR_UCU | \ + CHAFSR_WDU | CHAFSR_WDC) +#define MSYND_ERRORS (CHAFSR_EMC | CHAFSR_EMU) + if (afsr & ESYND_ERRORS) { + int syndrome; + int ret; + + syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT; + syndrome = cheetah_ecc_syntab[syndrome]; + ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); + if (ret != -1) + printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), + smp_processor_id(), unum); + } else if (afsr & MSYND_ERRORS) { + int syndrome; + int ret; + + syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT; + syndrome = cheetah_mtag_syntab[syndrome]; + ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); + if (ret != -1) + printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), + smp_processor_id(), unum); + } + + /* Now dump the cache snapshots. */ + printk("%s" "ERROR(%d): D-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (int) info->dcache_index, + info->dcache_tag, + info->dcache_utag, + info->dcache_stag); + printk("%s" "ERROR(%d): D-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->dcache_data[0], + info->dcache_data[1], + info->dcache_data[2], + info->dcache_data[3]); + printk("%s" "ERROR(%d): I-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx] " + "u[%016lx] l[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (int) info->icache_index, + info->icache_tag, + info->icache_utag, + info->icache_stag, + info->icache_upper, + info->icache_lower); + printk("%s" "ERROR(%d): I-cache INSN0[%016lx] INSN1[%016lx] INSN2[%016lx] INSN3[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->icache_data[0], + info->icache_data[1], + info->icache_data[2], + info->icache_data[3]); + printk("%s" "ERROR(%d): I-cache INSN4[%016lx] INSN5[%016lx] INSN6[%016lx] INSN7[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->icache_data[4], + info->icache_data[5], + info->icache_data[6], + info->icache_data[7]); + printk("%s" "ERROR(%d): E-cache idx[%x] tag[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + (int) info->ecache_index, info->ecache_tag); + printk("%s" "ERROR(%d): E-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n", + (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), + info->ecache_data[0], + info->ecache_data[1], + info->ecache_data[2], + info->ecache_data[3]); + + afsr = (afsr & ~hipri) & CHAFSR_ERRORS; + while (afsr != 0UL) { + unsigned long bit = cheetah_get_hipri(afsr); + + printk("%s" "ERROR: Multiple-error (%016lx) \"%s\"\n", + (recoverable ? KERN_WARNING : KERN_CRIT), + bit, cheetah_get_string(bit)); + + afsr &= ~bit; + } + + if (!recoverable) + printk(KERN_CRIT "ERROR: This condition is not recoverable.\n"); +} + +static int cheetah_recheck_errors(struct cheetah_err_info *logp) +{ + unsigned long afsr, afar; + int ret = 0; + + __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" + : "=r" (afsr) + : "i" (ASI_AFSR)); + if ((afsr & CHAFSR_ERRORS) != 0) { + if (logp != NULL) { + __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" + : "=r" (afar) + : "i" (ASI_AFAR)); + logp->afsr = afsr; + logp->afar = afar; + } + ret = 1; + } + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync\n\t" + : : "r" (afsr), "i" (ASI_AFSR)); + + return ret; +} + +void cheetah_fecc_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar) +{ + struct cheetah_err_info local_snapshot, *p; + int recoverable; + + /* Flush E-cache */ + cheetah_flush_ecache(); + + p = cheetah_get_error_log(afsr); + if (!p) { + prom_printf("ERROR: Early Fast-ECC error afsr[%016lx] afar[%016lx]\n", + afsr, afar); + prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate); + prom_halt(); + } + + /* Grab snapshot of logged error. */ + memcpy(&local_snapshot, p, sizeof(local_snapshot)); + + /* If the current trap snapshot does not match what the + * trap handler passed along into our args, big trouble. + * In such a case, mark the local copy as invalid. + * + * Else, it matches and we mark the afsr in the non-local + * copy as invalid so we may log new error traps there. + */ + if (p->afsr != afsr || p->afar != afar) + local_snapshot.afsr = CHAFSR_INVALID; + else + p->afsr = CHAFSR_INVALID; + + cheetah_flush_icache(); + cheetah_flush_dcache(); + + /* Re-enable I-cache/D-cache */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_DC | DCU_IC) + : "g1"); + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN) + : "g1"); + + /* Decide if we can continue after handling this trap and + * logging the error. + */ + recoverable = 1; + if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP)) + recoverable = 0; + + /* Re-check AFSR/AFAR. What we are looking for here is whether a new + * error was logged while we had error reporting traps disabled. + */ + if (cheetah_recheck_errors(&local_snapshot)) { + unsigned long new_afsr = local_snapshot.afsr; + + /* If we got a new asynchronous error, die... */ + if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU | + CHAFSR_WDU | CHAFSR_CPU | + CHAFSR_IVU | CHAFSR_UE | + CHAFSR_BERR | CHAFSR_TO)) + recoverable = 0; + } + + /* Log errors. */ + cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable); + + if (!recoverable) + panic("Irrecoverable Fast-ECC error trap.\n"); + + /* Flush E-cache to kick the error trap handlers out. */ + cheetah_flush_ecache(); +} + +/* Try to fix a correctable error by pushing the line out from + * the E-cache. Recheck error reporting registers to see if the + * problem is intermittent. + */ +static int cheetah_fix_ce(unsigned long physaddr) +{ + unsigned long orig_estate; + unsigned long alias1, alias2; + int ret; + + /* Make sure correctable error traps are disabled. */ + __asm__ __volatile__("ldxa [%%g0] %2, %0\n\t" + "andn %0, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %2\n\t" + "membar #Sync" + : "=&r" (orig_estate) + : "i" (ESTATE_ERROR_CEEN), + "i" (ASI_ESTATE_ERROR_EN) + : "g1"); + + /* We calculate alias addresses that will force the + * cache line in question out of the E-cache. Then + * we bring it back in with an atomic instruction so + * that we get it in some modified/exclusive state, + * then we displace it again to try and get proper ECC + * pushed back into the system. + */ + physaddr &= ~(8UL - 1UL); + alias1 = (ecache_flush_physbase + + (physaddr & ((ecache_flush_size >> 1) - 1))); + alias2 = alias1 + (ecache_flush_size >> 1); + __asm__ __volatile__("ldxa [%0] %3, %%g0\n\t" + "ldxa [%1] %3, %%g0\n\t" + "casxa [%2] %3, %%g0, %%g0\n\t" + "ldxa [%0] %3, %%g0\n\t" + "ldxa [%1] %3, %%g0\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (alias1), "r" (alias2), + "r" (physaddr), "i" (ASI_PHYS_USE_EC)); + + /* Did that trigger another error? */ + if (cheetah_recheck_errors(NULL)) { + /* Try one more time. */ + __asm__ __volatile__("ldxa [%0] %1, %%g0\n\t" + "membar #Sync" + : : "r" (physaddr), "i" (ASI_PHYS_USE_EC)); + if (cheetah_recheck_errors(NULL)) + ret = 2; + else + ret = 1; + } else { + /* No new error, intermittent problem. */ + ret = 0; + } + + /* Restore error enables. */ + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : : "r" (orig_estate), "i" (ASI_ESTATE_ERROR_EN)); + + return ret; +} + +/* Return non-zero if PADDR is a valid physical memory address. */ +static int cheetah_check_main_memory(unsigned long paddr) +{ + int i; + + for (i = 0; ; i++) { + if (sp_banks[i].num_bytes == 0) + break; + if (paddr >= sp_banks[i].base_addr && + paddr < (sp_banks[i].base_addr + sp_banks[i].num_bytes)) + return 1; + } + return 0; +} + +void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar) +{ + struct cheetah_err_info local_snapshot, *p; + int recoverable, is_memory; + + p = cheetah_get_error_log(afsr); + if (!p) { + prom_printf("ERROR: Early CEE error afsr[%016lx] afar[%016lx]\n", + afsr, afar); + prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate); + prom_halt(); + } + + /* Grab snapshot of logged error. */ + memcpy(&local_snapshot, p, sizeof(local_snapshot)); + + /* If the current trap snapshot does not match what the + * trap handler passed along into our args, big trouble. + * In such a case, mark the local copy as invalid. + * + * Else, it matches and we mark the afsr in the non-local + * copy as invalid so we may log new error traps there. + */ + if (p->afsr != afsr || p->afar != afar) + local_snapshot.afsr = CHAFSR_INVALID; + else + p->afsr = CHAFSR_INVALID; + + is_memory = cheetah_check_main_memory(afar); + + if (is_memory && (afsr & CHAFSR_CE) != 0UL) { + /* XXX Might want to log the results of this operation + * XXX somewhere... -DaveM + */ + cheetah_fix_ce(afar); + } + + { + int flush_all, flush_line; + + flush_all = flush_line = 0; + if ((afsr & CHAFSR_EDC) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDC) + flush_line = 1; + else + flush_all = 1; + } else if ((afsr & CHAFSR_CPC) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_CPC) + flush_line = 1; + else + flush_all = 1; + } + + /* Trap handler only disabled I-cache, flush it. */ + cheetah_flush_icache(); + + /* Re-enable I-cache */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_IC) + : "g1"); + + if (flush_all) + cheetah_flush_ecache(); + else if (flush_line) + cheetah_flush_ecache_line(afar); + } + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_CEEN) + : "g1"); + + /* Decide if we can continue after handling this trap and + * logging the error. + */ + recoverable = 1; + if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP)) + recoverable = 0; + + /* Re-check AFSR/AFAR */ + (void) cheetah_recheck_errors(&local_snapshot); + + /* Log errors. */ + cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable); + + if (!recoverable) + panic("Irrecoverable Correctable-ECC error trap.\n"); +} + +void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar) +{ + struct cheetah_err_info local_snapshot, *p; + int recoverable, is_memory; + +#ifdef CONFIG_PCI + /* Check for the special PCI poke sequence. */ + if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { + cheetah_flush_icache(); + cheetah_flush_dcache(); + + /* Re-enable I-cache/D-cache */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_DC | DCU_IC) + : "g1"); + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN) + : "g1"); + + (void) cheetah_recheck_errors(NULL); + + pci_poke_faulted = 1; + regs->tpc += 4; + regs->tnpc = regs->tpc + 4; + return; + } +#endif + + p = cheetah_get_error_log(afsr); + if (!p) { + prom_printf("ERROR: Early deferred error afsr[%016lx] afar[%016lx]\n", + afsr, afar); + prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate); + prom_halt(); + } + + /* Grab snapshot of logged error. */ + memcpy(&local_snapshot, p, sizeof(local_snapshot)); + + /* If the current trap snapshot does not match what the + * trap handler passed along into our args, big trouble. + * In such a case, mark the local copy as invalid. + * + * Else, it matches and we mark the afsr in the non-local + * copy as invalid so we may log new error traps there. + */ + if (p->afsr != afsr || p->afar != afar) + local_snapshot.afsr = CHAFSR_INVALID; + else + p->afsr = CHAFSR_INVALID; + + is_memory = cheetah_check_main_memory(afar); + + { + int flush_all, flush_line; + + flush_all = flush_line = 0; + if ((afsr & CHAFSR_EDU) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDU) + flush_line = 1; + else + flush_all = 1; + } else if ((afsr & CHAFSR_BERR) != 0UL) { + if ((afsr & CHAFSR_ERRORS) == CHAFSR_BERR) + flush_line = 1; + else + flush_all = 1; + } + + cheetah_flush_icache(); + cheetah_flush_dcache(); + + /* Re-enable I/D caches */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_DCU_CONTROL_REG), + "i" (DCU_IC | DCU_DC) + : "g1"); + + if (flush_all) + cheetah_flush_ecache(); + else if (flush_line) + cheetah_flush_ecache_line(afar); + } + + /* Re-enable error reporting */ + __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t" + "or %%g1, %1, %%g1\n\t" + "stxa %%g1, [%%g0] %0\n\t" + "membar #Sync" + : /* no outputs */ + : "i" (ASI_ESTATE_ERROR_EN), + "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN) + : "g1"); + + /* Decide if we can continue after handling this trap and + * logging the error. + */ + recoverable = 1; + if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP)) + recoverable = 0; + + /* Re-check AFSR/AFAR. What we are looking for here is whether a new + * error was logged while we had error reporting traps disabled. + */ + if (cheetah_recheck_errors(&local_snapshot)) { + unsigned long new_afsr = local_snapshot.afsr; + + /* If we got a new asynchronous error, die... */ + if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU | + CHAFSR_WDU | CHAFSR_CPU | + CHAFSR_IVU | CHAFSR_UE | + CHAFSR_BERR | CHAFSR_TO)) + recoverable = 0; + } + + /* Log errors. */ + cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable); + + /* "Recoverable" here means we try to yank the page from ever + * being newly used again. This depends upon a few things: + * 1) Must be main memory, and AFAR must be valid. + * 2) If we trapped from use, OK. + * 3) Else, if we trapped from kernel we must find exception + * table entry (ie. we have to have been accessing user + * space). + * + * If AFAR is not in main memory, or we trapped from kernel + * and cannot find an exception table entry, it is unacceptable + * to try and continue. + */ + if (recoverable && is_memory) { + if ((regs->tstate & TSTATE_PRIV) == 0UL) { + /* OK, usermode access. */ + recoverable = 1; + } else { + unsigned long g2 = regs->u_regs[UREG_G2]; + unsigned long fixup = search_exception_table(regs->tpc, &g2); + + if (fixup != 0UL) { + /* OK, kernel access to userspace. */ + recoverable = 1; + + } else { + /* BAD, privileged state is corrupted. */ + recoverable = 0; + } + + if (recoverable) { + struct page *page = virt_to_page(__va(afar)); + + if (VALID_PAGE(page)) + get_page(page); + else + recoverable = 0; + + /* Only perform fixup if we still have a + * recoverable condition. + */ + if (fixup != 0UL && recoverable) { + regs->tpc = fixup; + regs->tnpc = regs->tpc + 4; + regs->u_regs[UREG_G2] = g2; + } + } + } + } else { + recoverable = 0; + } + + if (!recoverable) + panic("Irrecoverable deferred error trap.\n"); +} + void do_fpe_common(struct pt_regs *regs) { if(regs->tstate & TSTATE_PRIV) { @@ -575,9 +1332,6 @@ void do_fpieee(struct pt_regs *regs) { -#ifdef DEBUG_FPU - printk("fpieee %016lx\n", current->thread.xfsr[0]); -#endif do_fpe_common(regs); } @@ -594,10 +1348,8 @@ ret = do_mathemu(regs, f); break; } - if (ret) return; -#ifdef DEBUG_FPU - printk("fpother %016lx\n", current->thread.xfsr[0]); -#endif + if (ret) + return; do_fpe_common(regs); } diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S --- v2.4.3/linux/arch/sparc64/kernel/ttable.S Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/ttable.S Thu Apr 12 12:10:25 2001 @@ -1,12 +1,16 @@ -/* $Id: ttable.S,v 1.32 2001/03/23 07:56:30 davem Exp $ - * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. +/* $Id: ttable.S,v 1.33 2001/03/28 10:56:34 davem Exp $ + * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu) */ #include <linux/config.h> - .globl sparc64_ttable_tl0, sparc64_ttable_tl1, + .globl sparc64_ttable_tl0, sparc64_ttable_tl1 + .globl tl0_fecc, tl1_fecc + .globl tl0_cee, tl1_cee + .globl tl0_iae, tl1_iae + .globl tl0_dae, tl1_dae sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) @@ -64,7 +68,8 @@ #include "dtlb_base.S" tl0_daprot: #include "dtlb_prot.S" -tl0_resv070: BTRAP(0x70) BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) +tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ +tl0_resv071: BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f) tl0_s0n: SPILL_0_NORMAL @@ -203,13 +208,30 @@ tl1_ivec: TRAP_IVEC tl1_paw: TRAPTL1(do_paw_tl1) tl1_vaw: TRAPTL1(do_vaw_tl1) -tl1_cee: TRAPTL1_CEE + + /* The grotty trick to save %g1 into current->thread.kernel_cntd0 + * is because when we take this trap we could be interrupting trap + * code already using the trap alternate global registers. It is + * better to corrupt a performance counter than corrupt trap register + * state. We cross our fingers and pray that this store/load does + * not cause yet another CEE trap. + */ +tl1_cee: membar #Sync + stx %g1, [%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0] + ldxa [%g0] ASI_AFSR, %g1 + membar #Sync + stxa %g1, [%g0] ASI_AFSR + membar #Sync + ldx [%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0], %g1 + retry + tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) tl1_damiss: #include "dtlb_backend.S" tl1_daprot: #include "dtlb_prot.S" -tl1_resv070: BTRAPTL1(0x70) BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73) +tl1_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ +tl1_resc071: BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73) tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77) tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b) tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f) diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c --- v2.4.3/linux/arch/sparc64/kernel/unaligned.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/unaligned.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.21 2001/03/21 11:46:20 davem Exp $ +/* $Id: unaligned.c,v 1.23 2001/04/09 04:29:03 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -12,6 +12,7 @@ #include <linux/mm.h> #include <asm/asi.h> #include <asm/ptrace.h> +#include <asm/pstate.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -376,6 +377,9 @@ regs->tpc = fixup; regs->tnpc = regs->tpc + 4; regs->u_regs [UREG_G2] = g2; + + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= (ASI_AIUS << 24UL); } asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/lib/bitops.S linux/arch/sparc64/lib/bitops.S --- v2.4.3/linux/arch/sparc64/lib/bitops.S Thu Mar 30 16:54:53 2000 +++ linux/arch/sparc64/lib/bitops.S Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: bitops.S,v 1.1 2000/03/27 10:38:41 davem Exp $ +/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $ * bitops.S: Sparc64 atomic bit operations. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -11,8 +11,8 @@ .globl __bitops_begin __bitops_begin: - .globl __test_and_set_bit -__test_and_set_bit: /* %o0=nr, %o1=addr */ + .globl ___test_and_set_bit +___test_and_set_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 sllx %g1, 3, %g3 @@ -30,8 +30,8 @@ 2: retl nop - .globl __test_and_clear_bit -__test_and_clear_bit: /* %o0=nr, %o1=addr */ + .globl ___test_and_clear_bit +___test_and_clear_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 sllx %g1, 3, %g3 @@ -49,8 +49,8 @@ 2: retl nop - .globl __test_and_change_bit -__test_and_change_bit: /* %o0=nr, %o1=addr */ + .globl ___test_and_change_bit +___test_and_change_bit: /* %o0=nr, %o1=addr */ srlx %o0, 6, %g1 mov 1, %g5 sllx %g1, 3, %g3 @@ -68,8 +68,8 @@ nop nop - .globl __test_and_set_le_bit -__test_and_set_le_bit: /* %o0=nr, %o1=addr */ + .globl ___test_and_set_le_bit +___test_and_set_le_bit: /* %o0=nr, %o1=addr */ srlx %o0, 5, %g1 mov 1, %g5 sllx %g1, 2, %g3 @@ -87,8 +87,8 @@ 2: retl nop - .globl __test_and_clear_le_bit -__test_and_clear_le_bit: /* %o0=nr, %o1=addr */ + .globl ___test_and_clear_le_bit +___test_and_clear_le_bit: /* %o0=nr, %o1=addr */ srlx %o0, 5, %g1 mov 1, %g5 sllx %g1, 2, %g3 diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.4.3/linux/arch/sparc64/lib/blockops.S Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/lib/blockops.S Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.30 2001/03/22 13:10:10 davem Exp $ +/* $Id: blockops.S,v 1.31 2001/04/05 11:08:12 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com) @@ -399,7 +399,6 @@ jmpl %o7 + 0x8, %g0 wrpr %g3, 0x0, %pstate - /* We will write cheetah optimized versions later. */ .globl cheetah_patch_pgcopyops cheetah_patch_pgcopyops: sethi %hi(FIX_INSN_1), %g1 diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c --- v2.4.3/linux/arch/sparc64/mm/generic.c Mon Mar 26 15:42:57 2001 +++ linux/arch/sparc64/mm/generic.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.16 2001/03/25 04:40:05 davem Exp $ +/* $Id: generic.c,v 1.17 2001/04/09 04:08:06 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/swap.h> +#include <linux/pagemap.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> @@ -21,11 +22,7 @@ struct page *ptpage = pte_page(page); if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) return; - /* - * free_page() used to be able to clear swap cache - * entries. We may now have to do it manually. - */ - free_page_and_swap_cache(ptpage); + page_cache_release(ptpage); return; } swap_free(pte_to_swp_entry(page)); diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.4.3/linux/arch/sparc64/mm/init.c Mon Mar 26 15:30:06 2001 +++ linux/arch/sparc64/mm/init.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.172 2001/03/24 09:36:01 davem Exp $ +/* $Id: init.c,v 1.174 2001/03/30 07:10:42 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -1126,6 +1126,7 @@ /* paging_init() sets up the page tables */ extern void sun_serial_setup(void); +extern void cheetah_ecache_flush_init(void); static unsigned long last_valid_pfn; @@ -1466,6 +1467,9 @@ datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); + + if (tlb_type == cheetah) + cheetah_ecache_flush_init(); } void free_initmem (void) diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c --- v2.4.3/linux/arch/sparc64/mm/modutil.c Sun Feb 18 19:49:54 2001 +++ linux/arch/sparc64/mm/modutil.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: modutil.c,v 1.7 2001/02/13 01:16:44 davem Exp $ +/* $Id: modutil.c,v 1.8 2001/04/04 00:49:39 davem Exp $ * arch/sparc64/mm/modutil.c * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -59,7 +59,7 @@ *p = area; if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) { - vfree(addr); + module_unmap(addr); return NULL; } return addr; diff -u --recursive --new-file v2.4.3/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c --- v2.4.3/linux/arch/sparc64/solaris/timod.c Fri Aug 4 18:16:11 2000 +++ linux/arch/sparc64/solaris/timod.c Fri Apr 13 20:26:07 2001 @@ -611,7 +611,7 @@ return 0; } default: - printk("timod_putmsg: unsuported command %u.\n", ret); + printk("timod_putmsg: unsupported command %u.\n", ret); break; } return -EINVAL; diff -u --recursive --new-file v2.4.3/linux/drivers/acpi/namespace/nsxfobj.c linux/drivers/acpi/namespace/nsxfobj.c --- v2.4.3/linux/drivers/acpi/namespace/nsxfobj.c Fri Feb 9 11:45:58 2001 +++ linux/drivers/acpi/namespace/nsxfobj.c Sun Apr 8 10:02:56 2001 @@ -592,7 +592,7 @@ status = acpi_cm_execute_STA (node, &flags); if (ACPI_FAILURE (status)) { - return (status); + return AE_OK; } if (!(flags & 0x01)) { diff -u --recursive --new-file v2.4.3/linux/drivers/atm/firestream.c linux/drivers/atm/firestream.c --- v2.4.3/linux/drivers/atm/firestream.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/atm/firestream.c Wed Apr 11 19:02:30 2001 @@ -294,6 +294,8 @@ #endif +static int fs_keystream = 0; + #ifdef DEBUG /* I didn't forget to set this to zero before shipping. Hit me with a stick if you get this with the debug default not set to zero again. -- REW */ @@ -308,6 +310,7 @@ #endif MODULE_PARM(loopback, "i"); MODULE_PARM(num, "i"); +MODULE_PARM(fs_keystream, "i"); /* XXX Add rx_buf_sizes, and rx_pool_sizes As per request Amar. -- REW */ #endif @@ -377,7 +380,7 @@ -/* It seems the ATM forum recomends this horribly complicated 16bit +/* It seems the ATM forum recommends this horribly complicated 16bit * floating point format. Turns out the Ambassador uses the exact same * encoding. I just copied it over. If Mitch agrees, I'll move it over * to the atm_misc file or something like that. (and remove it from @@ -716,6 +719,8 @@ switch (STATUS_CODE (qe)) { + case 0x01: /* This is for AAL0 where we put the chip in streaming mode */ + /* Fall through */ case 0x02: /* Process a real txdone entry. */ tmp = qe->p0; @@ -796,6 +801,8 @@ /* Single buffer packet */ switch (STATUS_CODE (qe)) { + case 0x1: + /* Fall through for streaming mode */ case 0x2:/* Packet received OK.... */ if (atm_vcc) { skb = pe->skb; @@ -877,7 +884,9 @@ if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR, &atm_vcc->flags); - if (atm_vcc->qos.aal != ATM_AAL5) return -EINVAL; /* XXX AAL0 */ + if ((atm_vcc->qos.aal != ATM_AAL5) && + (atm_vcc->qos.aal != ATM_AAL2)) + return -EINVAL; /* XXX AAL0 */ fs_dprintk (FS_DEBUG_OPEN, "fs: (itf %d): open %d.%d\n", atm_vcc->dev->number, atm_vcc->vpi, atm_vcc->vci); @@ -946,12 +955,27 @@ need to wait for completion anyway, to see if it completed succesfully. */ - tc->flags = 0 + switch (atm_vcc->qos.aal) { + case ATM_AAL2: + case ATM_AAL0: + tc->flags = 0 + | TC_FLAGS_TRANSPARENT_PAYLOAD + | TC_FLAGS_PACKET + | (1 << 28) + | TC_FLAGS_TYPE_UBR /* XXX Change to VBR -- PVDL */ + | TC_FLAGS_CAL0; + break; + case ATM_AAL5: + tc->flags = 0 | TC_FLAGS_AAL5 | TC_FLAGS_PACKET /* ??? */ | TC_FLAGS_TYPE_CBR | TC_FLAGS_CAL0; - + break; + default: + printk ("Unknown aal: %d\n", atm_vcc->qos.aal); + tc->flags = 0; + } /* Docs are vague about this atm_hdr field. By the way, the FS * chip makes odd errors if lower bits are set.... -- REW */ tc->atm_hdr = (vpi << 20) | (vci << 4); @@ -1025,7 +1049,6 @@ for (bfp = 0;bfp < FS_NR_FREE_POOLS; bfp++) if (atm_vcc->qos.rxtp.max_sdu <= dev->rx_fp[bfp].bufsize) break; - if (bfp >= FS_NR_FREE_POOLS) { fs_dprintk (FS_DEBUG_OPEN, "No free pool fits sdu: %d.\n", atm_vcc->qos.rxtp.max_sdu); @@ -1037,12 +1060,23 @@ return -EINVAL; } - submit_command (dev, &dev->hp_txq, - QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, - RC_FLAGS_AAL5 | - RC_FLAGS_BFPS_BFP * bfp | - RC_FLAGS_RXBM_PSB, 0, 0); - + switch (atm_vcc->qos.aal) { + case ATM_AAL0: + case ATM_AAL2: + submit_command (dev, &dev->hp_txq, + QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, + RC_FLAGS_TRANSP | + RC_FLAGS_BFPS_BFP * bfp | + RC_FLAGS_RXBM_PSB, 0, 0); + break; + case ATM_AAL5: + submit_command (dev, &dev->hp_txq, + QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo, + RC_FLAGS_AAL5 | + RC_FLAGS_BFPS_BFP * bfp | + RC_FLAGS_RXBM_PSB, 0, 0); + break; + }; if (IS_FS50 (dev)) { submit_command (dev, &dev->hp_txq, QE_CMD_REG_WR | QE_CMD_IMM_INQ, @@ -1697,7 +1731,7 @@ /* AN3: 10 */ write_fs (dev, SARMODE1, 0 - | (0 * SARMODE1_DEFHEC) /* XXX PHY */ + | (fs_keystream * SARMODE1_DEFHEC) /* XXX PHY */ | ((loopback == 1) * SARMODE1_TSTLP) /* XXX Loopback mode enable... */ | (1 * SARMODE1_DCRM) | (1 * SARMODE1_DCOAM) diff -u --recursive --new-file v2.4.3/linux/drivers/atm/firestream.h linux/drivers/atm/firestream.h --- v2.4.3/linux/drivers/atm/firestream.h Fri Dec 29 14:35:47 2000 +++ linux/drivers/atm/firestream.h Wed Apr 11 19:02:30 2001 @@ -369,6 +369,9 @@ }; #define TC_FLAGS_AAL5 (0x0 << 29) +#define TC_FLAGS_TRANSPARENT_PAYLOAD (0x1 << 29) +#define TC_FLAGS_TRANSPARENT_CELL (0x2 << 29) +#define TC_FLAGS_STREAMING (0x1 << 28) #define TC_FLAGS_PACKET (0x0) #define TC_FLAGS_TYPE_ABR (0x0 << 22) #define TC_FLAGS_TYPE_CBR (0x1 << 22) @@ -498,8 +501,8 @@ /* Within limits this is user-configurable. */ /* Note: Currently the sum (10 -> 1k channels) is hardcoded in the driver. */ -#define FS155_VPI_BITS 5 -#define FS155_VCI_BITS 5 +#define FS155_VPI_BITS 4 +#define FS155_VCI_BITS 6 #define FS155_CHANNEL_BITS (FS155_VPI_BITS + FS155_VCI_BITS) #define FS155_NR_CHANNELS (1 << FS155_CHANNEL_BITS) diff -u --recursive --new-file v2.4.3/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.4.3/linux/drivers/atm/zatm.c Tue Jul 18 14:55:01 2000 +++ linux/drivers/atm/zatm.c Wed Apr 11 19:02:30 2001 @@ -1826,9 +1826,13 @@ devs++; zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev),GFP_KERNEL); - if (!zatm_dev) break; + if (!zatm_dev) { + printk(KERN_EMERG "zatm.c: memory shortage\n"); + goto out; + } } } +out: return devs; } diff -u --recursive --new-file v2.4.3/linux/drivers/block/cciss.c linux/drivers/block/cciss.c --- v2.4.3/linux/drivers/block/cciss.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/block/cciss.c Fri Apr 13 20:26:07 2001 @@ -583,13 +583,15 @@ if (iocommand.Request.Type.Direction == XFER_WRITE) { /* Copy the data into the buffer we created */ - if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) + if (copy_from_user(buff, iocommand.buf, + iocommand.buf_size)) { + kfree(buff); return -EFAULT; + } } if ((c = cmd_alloc(NULL)) == NULL) { - if(buff!=NULL) - kfree(buff); + kfree(buff); return -ENOMEM; } // Fill in the command type @@ -636,8 +638,7 @@ if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) { cmd_free(NULL, c); - if (buff != NULL) - kfree(buff); + kfree(buff); return( -EFAULT); } @@ -648,11 +649,11 @@ { cmd_free(NULL, c); kfree(buff); + return -EFAULT; } } cmd_free(NULL, c); - if (buff != NULL) - kfree(buff); + kfree(buff); return(0); } @@ -761,7 +762,7 @@ hba[ctlr]->gendisk.nr_real = 0; /* - * Tell the array controller not to give us any interupts while + * Tell the array controller not to give us any interrupts while * we check the new geometry. Then turn interrupts back on when * we're done. */ @@ -1087,7 +1088,7 @@ if (timeout) status = 0; if(cmd->err_info->CommandStatus != 0) - { /* an error has occured */ + { /* an error has occurred */ switch(cmd->err_info->CommandStatus) { case CMD_TARGET_STATUS: @@ -1846,12 +1847,9 @@ || (hba[i]->errinfo_pool == NULL)) { nr_ctlr = i; - if(hba[i]->cmd_pool_bits) - kfree(hba[i]->cmd_pool_bits); - if(hba[i]->cmd_pool) - kfree(hba[i]->cmd_pool); - if(hba[i]->errinfo_pool) - kfree(hba[i]->errinfo_pool); + kfree(hba[i]->cmd_pool_bits); + kfree(hba[i]->cmd_pool); + kfree(hba[i]->errinfo_pool); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); num_cntlrs_reg--; diff -u --recursive --new-file v2.4.3/linux/drivers/block/cciss.h linux/drivers/block/cciss.h --- v2.4.3/linux/drivers/block/cciss.h Sat Feb 3 12:13:19 2001 +++ linux/drivers/block/cciss.h Fri Apr 13 20:26:07 2001 @@ -122,7 +122,7 @@ } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x08 turns them off... */ @@ -138,7 +138,7 @@ } } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x04 turns them off... */ diff -u --recursive --new-file v2.4.3/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h --- v2.4.3/linux/drivers/block/cciss_cmd.h Fri Sep 22 17:11:37 2000 +++ linux/drivers/block/cciss_cmd.h Fri Apr 13 20:26:07 2001 @@ -222,7 +222,7 @@ ErrDescriptor_struct ErrDesc; SGDescriptor_struct SG[MAXSGENTRIES]; /* information associated with the command */ - __u32 busaddr; /* physical addres of this record */ + __u32 busaddr; /* physical address of this record */ ErrorInfo_struct * err_info; /* pointer to the allocated mem */ int cmd_type; struct _CommandList_struct *prev; diff -u --recursive --new-file v2.4.3/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.4.3/linux/drivers/block/ll_rw_blk.c Fri Mar 23 11:45:28 2001 +++ linux/drivers/block/ll_rw_blk.c Thu Apr 12 12:15:52 2001 @@ -231,8 +231,7 @@ * If a driver processes several requests at once, it must remove them (or * at least all but one of them) from the request queue. * - * When a queue is plugged (see blk_queue_pluggable()) the head will be - * assumed to be inactive. + * When a queue is plugged the head will be assumed to be inactive. **/ void blk_queue_headactive(request_queue_t * q, int active) @@ -241,35 +240,6 @@ } /** - * blk_queue_pluggable - define a plugging function for a request queue - * @q: the request queue to which the function will apply - * @plug: the function to be called to plug a queue - * - * Description: - * A request queue will be "plugged" if a request is added to it - * while it is empty. This allows a number of requests to be added - * before any are processed, thus providing an opportunity for these - * requests to be merged or re-ordered. - * The default plugging function (generic_plug_device()) sets the - * "plugged" flag for the queue and adds a task to the $tq_disk task - * queue to unplug the queue and call the request function at a - * later time. - * - * A device driver may provide an alternate plugging function by - * passing it to blk_queue_pluggable(). This function should set - * the "plugged" flag if it want calls to the request_function to be - * blocked, and should place a task on $tq_disk which will unplug - * the queue. Alternately it can simply do nothing and there-by - * disable plugging of the device. - **/ - -void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug) -{ - q->plug_device_fn = plug; -} - - -/** * blk_queue_make_request - define an alternate make_request function for a device * @q: the request queue for the device to be affected * @mfn: the alternate make_request function @@ -590,7 +560,7 @@ list_add(&req->queue, insert_here); } -void inline blk_refill_freelist(request_queue_t *q, int rw) +inline void blk_refill_freelist(request_queue_t *q, int rw) { if (q->pending_free[rw]) { list_splice(&q->pending_freelist[rw], &q->request_freelist[rw]); @@ -602,7 +572,7 @@ /* * Must be called with io_request_lock held and interrupts disabled */ -void inline blkdev_release_request(struct request *req) +inline void blkdev_release_request(struct request *req) { request_queue_t *q = req->q; int rw = req->cmd; @@ -1320,15 +1290,19 @@ #ifdef CONFIG_DDV ddv_init(); #endif -#ifdef CONFIG_BLK_DEV_NBD - nbd_init(); -#endif #ifdef CONFIG_MDISK mdisk_init(); #endif #ifdef CONFIG_DASD dasd_init(); #endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_BLOCK) + tapeblock_init(); +#endif +#ifdef CONFIG_BLK_DEV_XPRAM + xpram_init(); +#endif + #ifdef CONFIG_SUN_JSFLASH jsfd_init(); #endif @@ -1343,7 +1317,6 @@ EXPORT_SYMBOL(__blk_get_queue); EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_queue_headactive); -EXPORT_SYMBOL(blk_queue_pluggable); EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(generic_make_request); EXPORT_SYMBOL(blkdev_release_request); diff -u --recursive --new-file v2.4.3/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.4.3/linux/drivers/block/loop.c Tue Mar 6 19:35:36 2001 +++ linux/drivers/block/loop.c Wed Apr 11 19:05:14 2001 @@ -316,7 +316,6 @@ static void loop_put_buffer(struct buffer_head *bh) { if (bh) { - kunmap(bh->b_page); __free_page(bh->b_page); kmem_cache_free(bh_cachep, bh); } @@ -408,9 +407,16 @@ * blocks... if highmem bounce buffering can get away with it, * so can we :-) */ - bh->b_page = alloc_page(GFP_BUFFER); - bh->b_data = kmap(bh->b_page); + do { + bh->b_page = alloc_page(GFP_BUFFER); + if (bh->b_page) + break; + + run_task_queue(&tq_disk); + schedule_timeout(HZ); + } while (1); + bh->b_data = page_address(bh->b_page); bh->b_end_io = loop_end_io_transfer; bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9); init_waitqueue_head(&bh->b_wait); @@ -455,6 +461,10 @@ * file backed, queue for loop_thread to handle */ if (lo->lo_flags & LO_FLAGS_DO_BMAP) { + /* + * rbh locked at this point, noone else should clear + * the dirty flag + */ if (rw == WRITE) set_bit(BH_Dirty, &rbh->b_state); loop_add_bh(lo, rbh); @@ -469,7 +479,8 @@ IV = loop_get_iv(lo, bh->b_rsector); if (rw == WRITE) { set_bit(BH_Dirty, &bh->b_state); - if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data, bh->b_size, IV)) + if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data, + bh->b_size, IV)) goto err; } diff -u --recursive --new-file v2.4.3/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.4.3/linux/drivers/block/nbd.c Tue Mar 6 19:19:21 2001 +++ linux/drivers/block/nbd.c Wed Apr 11 19:02:30 2001 @@ -26,12 +26,11 @@ * structure with userland */ -#undef NBD_PLUGGABLE #define PARANOIA #include <linux/major.h> #include <linux/module.h> - +#include <linux/init.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/stat.h> @@ -68,8 +67,6 @@ static int requests_out; #endif -static void nbd_plug_device(request_queue_t *q, kdev_t dev) { } - static int nbd_open(struct inode *inode, struct file *file) { int dev; @@ -88,7 +85,7 @@ /* * Send or receive packet. */ -static int nbd_xmit(int send, struct socket *sock, char *buf, int size) +static int nbd_xmit(int send, struct socket *sock, char *buf, int size, int msg_flags) { mm_segment_t oldfs; int result; @@ -118,7 +115,7 @@ msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_namelen = 0; - msg.msg_flags = 0; + msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (send) result = sock_sendmsg(sock, &msg, size); @@ -151,23 +148,28 @@ { int result; struct nbd_request request; + unsigned long size = req->nr_sectors << 9; DEBUG("NBD: sending control, "); request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(req->cmd); request.from = cpu_to_be64( (u64) req->sector << 9); - request.len = htonl(req->current_nr_sectors << 9); + request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); - result = nbd_xmit(1, sock, (char *) &request, sizeof(request)); + result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0); if (result <= 0) FAIL("Sendmsg failed for control."); if (req->cmd == WRITE) { + struct buffer_head *bh = req->bh; DEBUG("data, "); - result = nbd_xmit(1, sock, req->buffer, req->current_nr_sectors << 9); - if (result <= 0) - FAIL("Send data failed."); + do { + result = nbd_xmit(1, sock, bh->b_data, bh->b_size, bh->b_reqnext == NULL ? 0 : MSG_MORE); + if (result <= 0) + FAIL("Send data failed."); + bh = bh->b_reqnext; + } while(bh); } return; @@ -185,7 +187,7 @@ DEBUG("reading control, "); reply.magic = 0; - result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply)); + result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply), MSG_WAITALL); if (result <= 0) HARDFAIL("Recv control failed."); memcpy(&xreq, reply.handle, sizeof(xreq)); @@ -200,10 +202,14 @@ if (ntohl(reply.error)) FAIL("Other side returned error."); if (req->cmd == READ) { + struct buffer_head *bh = req->bh; DEBUG("data, "); - result = nbd_xmit(0, lo->sock, req->buffer, req->current_nr_sectors << 9); - if (result <= 0) - HARDFAIL("Recv data failed."); + do { + result = nbd_xmit(0, lo->sock, bh->b_data, bh->b_size, MSG_WAITALL); + if (result <= 0) + HARDFAIL("Recv data failed."); + bh = bh->b_reqnext; + } while(bh); } DEBUG("done.\n"); return req; @@ -217,7 +223,6 @@ void nbd_do_it(struct nbd_device *lo) { struct request *req; - int dequeued; down (&lo->queue_lock); while (1) { @@ -245,11 +250,9 @@ list_del(&req->queue); up (&lo->queue_lock); - dequeued = nbd_end_request(req); + nbd_end_request(req); down (&lo->queue_lock); - if (!dequeued) - list_add(&req->queue, &lo->queue_head); } out: up (&lo->queue_lock); @@ -258,7 +261,6 @@ void nbd_clear_que(struct nbd_device *lo) { struct request *req; - int dequeued; #ifdef PARANOIA if (lo->magic != LO_MAGIC) { @@ -283,11 +285,9 @@ list_del(&req->queue); up(&lo->queue_lock); - dequeued = nbd_end_request(req); + nbd_end_request(req); down(&lo->queue_lock); - if (!dequeued) - list_add(&req->queue, &lo->queue_head); } } @@ -477,11 +477,7 @@ * (Just smiley confuses emacs :-) */ -#ifdef MODULE -#define nbd_init init_module -#endif - -int nbd_init(void) +static int __init nbd_init(void) { int i; @@ -501,9 +497,6 @@ blksize_size[MAJOR_NR] = nbd_blksizes; blk_size[MAJOR_NR] = nbd_sizes; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request); -#ifndef NBD_PLUGGABLE - blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), nbd_plug_device); -#endif blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); for (i = 0; i < MAX_NBD; i++) { nbd_dev[i].refcnt = 0; @@ -528,8 +521,7 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit nbd_cleanup(void) { devfs_unregister (devfs_handle); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); @@ -539,4 +531,9 @@ else printk("nbd: module cleaned up.\n"); } -#endif + +module_init(nbd_init); +module_exit(nbd_cleanup); + +MODULE_DESCRIPTION("Network Block Device"); + diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in --- v2.4.3/linux/drivers/block/paride/Config.in Mon Jan 24 11:21:47 2000 +++ linux/drivers/block/paride/Config.in Fri Apr 6 10:42:55 2001 @@ -20,7 +20,8 @@ dep_tristate ' Parallel port generic ATAPI devices' CONFIG_PARIDE_PG $CONFIG_PARIDE comment 'Parallel IDE protocol modules' dep_tristate ' ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE -dep_tristate ' MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE +dep_tristate ' MicroSolutions backpack (Series 5) protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE +dep_tristate ' MicroSolutions backpack (Series 6) protocol' CONFIG_PARIDE_BPCK6 $CONFIG_PARIDE dep_tristate ' DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE dep_tristate ' DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE dep_tristate ' FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/Makefile linux/drivers/block/paride/Makefile --- v2.4.3/linux/drivers/block/paride/Makefile Fri Dec 29 14:07:21 2000 +++ linux/drivers/block/paride/Makefile Fri Apr 6 10:42:55 2001 @@ -27,5 +27,6 @@ obj-$(CONFIG_PARIDE_ON20) += on20.o obj-$(CONFIG_PARIDE_ON26) += on26.o obj-$(CONFIG_PARIDE_KTTI) += ktti.o +obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/bpck6.c linux/drivers/block/paride/bpck6.c --- v2.4.3/linux/drivers/block/paride/bpck6.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/paride/bpck6.c Thu Apr 12 12:16:35 2001 @@ -0,0 +1,317 @@ +/* + backpack.c (c) 2001 Micro Solutions Inc. + Released under the terms of the GNU General Public license + + backpack.c is a low-level protocol driver for the Micro Solutions + "BACKPACK" parallel port IDE adapter + (Works on Series 6 drives) + + Written by: Ken Hahn (linux-dev@micro-solutions.com) + Clive Turvey (linux-dev@micro-solutions.com) + +*/ + +/* + This is Ken's linux wrapper for the PPC library + Version 1.0.0 is the backpack driver for which source is not available + Version 2.0.0 is the first to have source released + Version 2.0.1 is the "Cox-ified" source code + Version 2.0.2 - fixed version string usage, and made ppc functions static +*/ + + +/* PARAMETERS */ +int verbose=0; /* set this to 1 to see debugging messages and whatnot */ + +#define BACKPACK_VERSION "2.0.2" + +#define EXPORT_SYMTAB +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/types.h> +#include <asm/io.h> + +#if defined(CONFIG_PARPORT_MODULE)||defined(CONFIG_PARPORT) +#include <linux/parport.h> +#endif + +#include "ppc6lnx.c" +#include "paride.h" + + + +#define PPCSTRUCT(pi) ((PPC *)(pi->private)) + +/****************************************************************/ +/* + ATAPI CDROM DRIVE REGISTERS +*/ +#define ATAPI_DATA 0 /* data port */ +#define ATAPI_ERROR 1 /* error register (read) */ +#define ATAPI_FEATURES 1 /* feature register (write) */ +#define ATAPI_INT_REASON 2 /* interrupt reason register */ +#define ATAPI_COUNT_LOW 4 /* byte count register (low) */ +#define ATAPI_COUNT_HIGH 5 /* byte count register (high) */ +#define ATAPI_DRIVE_SEL 6 /* drive select register */ +#define ATAPI_STATUS 7 /* status port (read) */ +#define ATAPI_COMMAND 7 /* command port (write) */ +#define ATAPI_ALT_STATUS 0x0e /* alternate status reg (read) */ +#define ATAPI_DEVICE_CONTROL 0x0e /* device control (write) */ +/****************************************************************/ + +static int bpck6_read_regr(PIA *pi, int cont, int reg) +{ + unsigned int out; + + /* check for bad settings */ + if (reg<0 || reg>7 || cont<0 || cont>2) + { + return(-1); + } + out=ppc6_rd_port(PPCSTRUCT(pi),cont?reg|8:reg); + return(out); +} + +static void bpck6_write_regr(PIA *pi, int cont, int reg, int val) +{ + /* check for bad settings */ + if (reg>=0 && reg<=7 && cont>=0 && cont<=1) + { + ppc6_wr_port(PPCSTRUCT(pi),cont?reg|8:reg,(u8)val); + } +} + +static void bpck6_write_block( PIA *pi, char * buf, int len ) +{ + ppc6_wr_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); +} + +static void bpck6_read_block( PIA *pi, char * buf, int len ) +{ + ppc6_rd_port16_blk(PPCSTRUCT(pi),ATAPI_DATA,buf,(u32)len>>1); +} + +static void bpck6_connect ( PIA *pi ) +{ + if(verbose) + { + printk(KERN_DEBUG "connect\n"); + } + + if(pi->mode >=2) + { + PPCSTRUCT(pi)->mode=4+pi->mode-2; + } + else if(pi->mode==1) + { + PPCSTRUCT(pi)->mode=3; + } + else + { + PPCSTRUCT(pi)->mode=1; + } + + ppc6_open(PPCSTRUCT(pi)); + ppc6_wr_extout(PPCSTRUCT(pi),0x3); +} + +static void bpck6_disconnect ( PIA *pi ) +{ + if(verbose) + { + printk("disconnect\n"); + } + ppc6_wr_extout(PPCSTRUCT(pi),0x0); + ppc6_close(PPCSTRUCT(pi)); +} + +static int bpck6_test_port ( PIA *pi ) /* check for 8-bit port */ +{ + if(verbose) + { + printk(KERN_DEBUG "PARPORT indicates modes=%x for lp=0x%lx\n", + ((struct pardevice*)(pi->pardev))->port->modes, + ((struct pardevice *)(pi->pardev))->port->base); + } + + /*copy over duplicate stuff.. initialize state info*/ + PPCSTRUCT(pi)->ppc_id=pi->unit; + PPCSTRUCT(pi)->lpt_addr=pi->port; + +#ifdef CONFIG_PARPORT_PC_MODULE +#define CONFIG_PARPORT_PC +#endif + +#ifdef CONFIG_PARPORT_PC + /* look at the parport device to see if what modes we can use */ + if(((struct pardevice *)(pi->pardev))->port->modes & + (PARPORT_MODE_EPP) + ) + { + return 5; /* Can do EPP*/ + } + else if(((struct pardevice *)(pi->pardev))->port->modes & + (PARPORT_MODE_TRISTATE) + ) + { + return 2; + } + else /*Just flat SPP*/ + { + return 1; + } +#else + /* there is no way of knowing what kind of port we have + default to the highest mode possible */ + return 5; +#endif +} + +static int bpck6_probe_unit ( PIA *pi ) +{ + int out; + + if(verbose) + { + printk(KERN_DEBUG "PROBE UNIT %x on port:%x\n",pi->unit,pi->port); + } + + /*SET PPC UNIT NUMBER*/ + PPCSTRUCT(pi)->ppc_id=pi->unit; + + /*LOWER DOWN TO UNIDIRECTIONAL*/ + PPCSTRUCT(pi)->mode=1; + + out=ppc6_open(PPCSTRUCT(pi)); + + if(verbose) + { + printk(KERN_DEBUG "ppc_open returned %2x\n",out); + } + + if(out) + { + ppc6_close(PPCSTRUCT(pi)); + return(1); + if(verbose) + { + printk(KERN_DEBUG "leaving probe\n"); + } + } + else + { + if(verbose) + { + printk(KERN_DEBUG "Failed open\n"); + } + return(0); + } +} + +static void bpck6_log_adapter( PIA *pi, char * scratch, int verbose ) +{ + char *mode_string[5]= + {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"}; + + printk("%s: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n",pi->device); + printk("%s: Copyright 2001 by Micro Solutions, Inc., DeKalb IL.\n",pi->device); + printk("%s: BACKPACK %s, Micro Solutions BACKPACK Drive at 0x%x\n", + pi->device,BACKPACK_VERSION,pi->port); + printk("%s: Unit: %d Mode:%d (%s) Delay %d\n",pi->device, + pi->unit,pi->mode,mode_string[pi->mode],pi->delay); +} + +static void bpck6_init_proto(PIA *pi) +{ + int i; + + /* allocate a state structure for this item */ + pi->private=(int)kmalloc(sizeof(PPC),GFP_KERNEL); + + if(pi->private==(int)NULL) + { + printk(KERN_ERR "%s: ERROR COULDN'T ALLOCATE MEMORY\n",pi->device); + return; + } + else + { + MOD_INC_USE_COUNT; + } + + for(i=0;i<sizeof(PPC);i++) + { + ((unsigned char *)(pi->private))[i]=0; + } +} + +static void bpck6_release_proto(PIA *pi) +{ + MOD_DEC_USE_COUNT; + /* free after use count decremented so that we aren't using it + when it is decremented */ + kfree((void *)(pi->private)); +} + +struct pi_protocol bpck6 = { "bpck6", /* name for proto*/ + 0, /* index into proto table */ + 5, /* max mode =5 */ + 2, /* 2-5 use epp (need 8 ports) */ + 0, /* no delay (not used anyway) */ + 255, /* we can have units up to 255 */ + bpck6_write_regr, + bpck6_read_regr, + bpck6_write_block, + bpck6_read_block, + bpck6_connect, + bpck6_disconnect, + bpck6_test_port, + bpck6_probe_unit, + 0, + bpck6_log_adapter, + bpck6_init_proto, + bpck6_release_proto + }; + + +EXPORT_SYMBOL(bpck6_write_regr); +EXPORT_SYMBOL(bpck6_read_regr); +EXPORT_SYMBOL(bpck6_write_block); +EXPORT_SYMBOL(bpck6_read_block); +EXPORT_SYMBOL(bpck6_connect); +EXPORT_SYMBOL(bpck6_disconnect); +EXPORT_SYMBOL(bpck6_test_port); +EXPORT_SYMBOL(bpck6_probe_unit); +EXPORT_SYMBOL(bpck6_log_adapter); +EXPORT_SYMBOL(bpck6_init_proto); +EXPORT_SYMBOL(bpck6_release_proto); + +/*---------------------------MODULE STUFF-----------------------*/ + +#ifdef MODULE +/*module information*/ + +static int init_module(void) +{ + printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n"); + printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n"); + + if(verbose) + { + printk(KERN_DEBUG "bpck6: verbose debug enabled.\n"); + } + + return pi_register(&bpck6) - 1; +} + +void cleanup_module(void) +{ + pi_unregister(&bpck6); +} + +MODULE_AUTHOR("Micro Solutions Inc."); +MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE"); +MODULE_PARM(verbose,"i"); + +#endif + diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c --- v2.4.3/linux/drivers/block/paride/paride.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/block/paride/paride.c Fri Apr 6 10:42:55 2001 @@ -15,9 +15,10 @@ 1.04 GRG 1998.11.28 added support for FRIQ 1.05 TMW 2000.06.06 use parport_find_number instead of parport_enumerate + 1.06 TMW 2001.03.26 more sane parport-or-not resource management */ -#define PI_VERSION "1.05" +#define PI_VERSION "1.06" #include <linux/module.h> #include <linux/config.h> @@ -160,8 +161,10 @@ void pi_release( PIA *pi) { pi_unregister_parport(pi); - if ((!pi->pardev)&&(pi->reserved)) +#ifndef CONFIG_PARPORT + if (pi->reserved) release_region(pi->port,pi->reserved); +#endif /* !CONFIG_PARPORT */ pi->proto->release_proto(pi); } @@ -234,7 +237,7 @@ MOD_DEC_USE_COUNT; } -static void pi_register_parport( PIA *pi, int verbose) +static int pi_register_parport( PIA *pi, int verbose) { #ifdef CONFIG_PARPORT @@ -242,15 +245,16 @@ struct parport *port; port = parport_find_base (pi->port); - if (!port) return; + if (!port) + return 0; pi->pardev = parport_register_device(port, pi->device,NULL, pi_wake_up,NULL, 0,(void *)pi); parport_put_port (port); - if (!pi->pardev) return; - + if (!pi->pardev) + return 0; init_waitqueue_head(&pi->parq); @@ -258,8 +262,9 @@ port->name); pi->parname = (char *)port->name; - #endif + + return 1; } static int pi_probe_mode( PIA *pi, int max, char * scratch, int verbose) @@ -271,7 +276,9 @@ range = 3; if (pi->mode >= pi->proto->epp_first) range = 8; if ((range == 8) && (pi->port % 8)) return 0; - if ((!pi->pardev) && check_region(pi->port,range)) return 0; +#ifndef CONFIG_PARPORT + if (check_region(pi->port,range)) return 0; +#endif /* !CONFIG_PARPORT */ pi->reserved = range; return (!pi_test_proto(pi,scratch,verbose)); } @@ -280,7 +287,9 @@ range = 3; if (pi->mode >= pi->proto->epp_first) range = 8; if ((range == 8) && (pi->port % 8)) break; - if ((!pi->pardev) && check_region(pi->port,range)) break; +#ifndef CONFIG_PARPORT + if (check_region(pi->port,range)) break; +#endif /* !CONFIG_PARPORT */ pi->reserved = range; if (!pi_test_proto(pi,scratch,verbose)) best = pi->mode; } @@ -299,9 +308,12 @@ e = pi->proto->max_units; } - pi_register_parport(pi,verbose); + if (!pi_register_parport(pi,verbose)) + return 0; - if ((!pi->pardev) && check_region(pi->port,3)) return 0; +#ifndef CONFIG_PARPORT + if (check_region(pi->port,3)) return 0; +#endif /* !CONFIG_PARPORT */ if (pi->proto->test_port) { pi_claim(pi); @@ -391,8 +403,9 @@ return 0; } - if (!pi->pardev) - request_region(pi->port,pi->reserved,pi->device); +#ifndef CONFIG_PARPORT + request_region(pi->port,pi->reserved,pi->device); +#endif /* !CONFIG_PARPORT */ if (pi->parname) printk("%s: Sharing %s at 0x%x\n",pi->device, @@ -407,11 +420,16 @@ int init_module(void) -{ int k; +{ + int k; + const char *indicate_pp = ""; +#ifdef CONFIG_PARPORT + indicate_pp = " (parport)"; +#endif for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0; - printk("paride: version %s installed\n",PI_VERSION); + printk("paride: version %s installed%s\n",PI_VERSION,indicate_pp); return 0; } diff -u --recursive --new-file v2.4.3/linux/drivers/block/paride/ppc6lnx.c linux/drivers/block/paride/ppc6lnx.c --- v2.4.3/linux/drivers/block/paride/ppc6lnx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/paride/ppc6lnx.c Fri Apr 6 10:42:55 2001 @@ -0,0 +1,950 @@ +/* + ppc6lnx.c (c) 2001 Micro Solutions Inc. + Released under the terms of the GNU General Public license + + ppc6lnx.c is a par of the protocol driver for the Micro Solutions + "BACKPACK" parallel port IDE adapter + (Works on Series 6 drives) + +*/ + +//*************************************************************************** + +// PPC 6 Code in C sanitized for LINUX +// Original x86 ASM by Ron, Converted to C by Clive + +//*************************************************************************** + + +#define port_stb 1 +#define port_afd 2 +#define cmd_stb port_afd +#define port_init 4 +#define data_stb port_init +#define port_sel 8 +#define port_int 16 +#define port_dir 0x20 + +#define ECR_EPP 0x80 +#define ECR_BI 0x20 + +//*************************************************************************** + +// 60772 Commands + +#define ACCESS_REG 0x00 +#define ACCESS_PORT 0x40 + +#define ACCESS_READ 0x00 +#define ACCESS_WRITE 0x20 + +// 60772 Command Prefix + +#define CMD_PREFIX_SET 0xe0 // Special command that modifies the next command's operation +#define CMD_PREFIX_RESET 0xc0 // Resets current cmd modifier reg bits + #define PREFIX_IO16 0x01 // perform 16-bit wide I/O + #define PREFIX_FASTWR 0x04 // enable PPC mode fast-write + #define PREFIX_BLK 0x08 // enable block transfer mode + +// 60772 Registers + +#define REG_STATUS 0x00 // status register + #define STATUS_IRQA 0x01 // Peripheral IRQA line + #define STATUS_EEPROM_DO 0x40 // Serial EEPROM data bit +#define REG_VERSION 0x01 // PPC version register (read) +#define REG_HWCFG 0x02 // Hardware Config register +#define REG_RAMSIZE 0x03 // Size of RAM Buffer + #define RAMSIZE_128K 0x02 +#define REG_EEPROM 0x06 // EEPROM control register + #define EEPROM_SK 0x01 // eeprom SK bit + #define EEPROM_DI 0x02 // eeprom DI bit + #define EEPROM_CS 0x04 // eeprom CS bit + #define EEPROM_EN 0x08 // eeprom output enable +#define REG_BLKSIZE 0x08 // Block transfer len (24 bit) + +//*************************************************************************** + +typedef struct ppc_storage { + u16 lpt_addr; // LPT base address + u8 ppc_id; + u8 mode; // operating mode + // 0 = PPC Uni SW + // 1 = PPC Uni FW + // 2 = PPC Bi SW + // 3 = PPC Bi FW + // 4 = EPP Byte + // 5 = EPP Word + // 6 = EPP Dword + u8 ppc_flags; + u8 org_data; // original LPT data port contents + u8 org_ctrl; // original LPT control port contents + u8 cur_ctrl; // current control port contents +} PPC; + +//*************************************************************************** + +// ppc_flags + +#define fifo_wait 0x10 + +//*************************************************************************** + +// DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES + +#define PPCMODE_UNI_SW 0 +#define PPCMODE_UNI_FW 1 +#define PPCMODE_BI_SW 2 +#define PPCMODE_BI_FW 3 +#define PPCMODE_EPP_BYTE 4 +#define PPCMODE_EPP_WORD 5 +#define PPCMODE_EPP_DWORD 6 + +//*************************************************************************** + +static int ppc6_select(PPC *ppc); +static void ppc6_deselect(PPC *ppc); +static void ppc6_send_cmd(PPC *ppc, u8 cmd); +static void ppc6_wr_data_byte(PPC *ppc, u8 data); +static u8 ppc6_rd_data_byte(PPC *ppc); +static u8 ppc6_rd_port(PPC *ppc, u8 port); +static void ppc6_wr_port(PPC *ppc, u8 port, u8 data); +static u8 ppc6_rd_reg(PPC *ppc, u8 reg); +static void ppc6_wr_reg(PPC *ppc, u8 reg, u8 data); +static u8 ppc6_version(PPC *ppc); +static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count); +static void ppc6_wait_for_fifo(PPC *ppc); +static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count); +static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length); +static u16 ppc6_rd_port16(PPC *ppc, u8 port); +static void ppc6_wr_port16(PPC *ppc, u8 port, u16 data); +static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length); +static u8 ppc6_rd_eeprom_reg(PPC *ppc); +static void ppc6_wr_eeprom_reg(PPC *ppc, u8 data); +static void ppc6_eeprom_start(PPC *ppc); +static void ppc6_eeprom_end(PPC *ppc); +static void ppc6_set_cs(PPC *ppc); +static void ppc6_reset_cs(PPC *ppc); +static u8 ppc6_rd_eeprom_bit(PPC *ppc); +static void ppc6_eeprom_ready_wait(PPC *ppc); +static void ppc6_wr_eeprom_bit(PPC *ppc, u8 bit); +static u16 ppc6_eeprom_read(PPC *ppc, u8 addr); +static u8 ppc6_irq_test(PPC *ppc); +static u8 ppc6_rd_extout(PPC *ppc); +static void ppc6_wr_extout(PPC *ppc, u8 regdata); +static int ppc6_open(PPC *ppc); +static void ppc6_close(PPC *ppc); + +//*************************************************************************** + +static int ppc6_select(PPC *ppc) +{ + u8 i, j, k; + + i = inb(ppc->lpt_addr + 1); + + if (i & 1) + outb(i, ppc->lpt_addr + 1); + + ppc->org_data = inb(ppc->lpt_addr); + + ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl + + ppc->cur_ctrl = ppc->org_ctrl; + + ppc->cur_ctrl |= port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + if (ppc->org_data == 'b') + outb('x', ppc->lpt_addr); + + outb('b', ppc->lpt_addr); + outb('p', ppc->lpt_addr); + outb(ppc->ppc_id, ppc->lpt_addr); + outb(~ppc->ppc_id,ppc->lpt_addr); + + ppc->cur_ctrl &= ~port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + i = ppc->mode & 0x0C; + + if (i == 0) + i = (ppc->mode & 2) | 1; + + outb(i, ppc->lpt_addr); + + ppc->cur_ctrl |= port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + ppc->cur_ctrl |= port_afd; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + j = ((i & 0x08) << 4) | ((i & 0x07) << 3); + + k = inb(ppc->lpt_addr + 1) & 0xB8; + + if (j == k) + { + ppc->cur_ctrl &= ~port_afd; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8; + + if (j == k) + { + if (i & 4) // EPP + ppc->cur_ctrl &= ~(port_sel | port_init); + else // PPC/ECP + ppc->cur_ctrl &= ~port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + return(1); + } + } + + outb(ppc->org_ctrl, ppc->lpt_addr + 2); + + outb(ppc->org_data, ppc->lpt_addr); + + return(0); // FAIL +} + +//*************************************************************************** + +static void ppc6_deselect(PPC *ppc) +{ + if (ppc->mode & 4) // EPP + ppc->cur_ctrl |= port_init; + else // PPC/ECP + ppc->cur_ctrl |= port_sel; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + outb(ppc->org_data, ppc->lpt_addr); + + outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2); + + outb(ppc->org_ctrl, ppc->lpt_addr + 2); +} + +//*************************************************************************** + +static void ppc6_send_cmd(PPC *ppc, u8 cmd) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + outb(cmd, ppc->lpt_addr); + + ppc->cur_ctrl ^= cmd_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + case PPCMODE_EPP_WORD : + case PPCMODE_EPP_DWORD : + { + outb(cmd, ppc->lpt_addr + 3); + + break; + } + } +} + +//*************************************************************************** + +static void ppc6_wr_data_byte(PPC *ppc, u8 data) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + outb(data, ppc->lpt_addr); + + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + case PPCMODE_EPP_WORD : + case PPCMODE_EPP_DWORD : + { + outb(data, ppc->lpt_addr + 4); + + break; + } + } +} + +//*************************************************************************** + +static u8 ppc6_rd_data_byte(PPC *ppc) +{ + u8 data; + + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + { + ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + data = inb(ppc->lpt_addr + 1); + + data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3); + + ppc->cur_ctrl |= port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + data |= inb(ppc->lpt_addr + 1) & 0xB8; + + break; + } + + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + ppc->cur_ctrl |= port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + data = inb(ppc->lpt_addr); + + ppc->cur_ctrl &= ~port_stb; + + outb(ppc->cur_ctrl,ppc->lpt_addr + 2); + + ppc->cur_ctrl &= ~port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + case PPCMODE_EPP_WORD : + case PPCMODE_EPP_DWORD : + { + outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2); + + data = inb(ppc->lpt_addr + 4); + + outb(ppc->cur_ctrl,ppc->lpt_addr + 2); + + break; + } + } + + return(data); +} + +//*************************************************************************** + +static u8 ppc6_rd_port(PPC *ppc, u8 port) +{ + ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc)); +} + +//*************************************************************************** + +static void ppc6_wr_port(PPC *ppc, u8 port, u8 data) +{ + ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, data); +} + +//*************************************************************************** + +static u8 ppc6_rd_reg(PPC *ppc, u8 reg) +{ + ppc6_send_cmd(ppc,(u8)(reg | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc)); +} + +//*************************************************************************** + +static void ppc6_wr_reg(PPC *ppc, u8 reg, u8 data) +{ + ppc6_send_cmd(ppc,(u8)(reg | ACCESS_REG | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, data); +} + +//*************************************************************************** + +static u8 ppc6_version(PPC *ppc) +{ + ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc) & 0x3F); +} + +//*************************************************************************** + +static void ppc6_rd_data_blk(PPC *ppc, u8 *data, long count) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_UNI_FW : + { + while(count) + { + u8 d; + + ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + d = inb(ppc->lpt_addr + 1); + + d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3); + + ppc->cur_ctrl |= port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + // DELAY + + d |= inb(ppc->lpt_addr + 1) & 0xB8; + + *data++ = d; + count--; + } + + break; + } + + case PPCMODE_BI_SW : + case PPCMODE_BI_FW : + { + ppc->cur_ctrl |= port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl |= port_stb; + + while(count) + { + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + *data++ = inb(ppc->lpt_addr); + count--; + } + + ppc->cur_ctrl &= ~port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc->cur_ctrl &= ~port_dir; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_BYTE : + { + outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2); + + // DELAY + + while(count) + { + *data++ = inb(ppc->lpt_addr + 4); + count--; + } + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_WORD : + { + outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2); + + // DELAY + + while(count > 1) + { + *((u16 *)data) = inw(ppc->lpt_addr + 4); + data += 2; + count -= 2; + } + + while(count) + { + *data++ = inb(ppc->lpt_addr + 4); + count--; + } + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + + case PPCMODE_EPP_DWORD : + { + outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2); + + // DELAY + + while(count > 3) + { + *((u32 *)data) = inl(ppc->lpt_addr + 4); + data += 4; + count -= 4; + } + + while(count) + { + *data++ = inb(ppc->lpt_addr + 4); + count--; + } + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + break; + } + } + +} + +//*************************************************************************** + +static void ppc6_wait_for_fifo(PPC *ppc) +{ + int i; + + if (ppc->ppc_flags & fifo_wait) + { + for(i=0; i<20; i++) + inb(ppc->lpt_addr + 1); + } +} + +//*************************************************************************** + +static void ppc6_wr_data_blk(PPC *ppc, u8 *data, long count) +{ + switch(ppc->mode) + { + case PPCMODE_UNI_SW : + case PPCMODE_BI_SW : + { + while(count--) + { + outb(*data++, ppc->lpt_addr); + + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + } + + break; + } + + case PPCMODE_UNI_FW : + case PPCMODE_BI_FW : + { + u8 this, last; + + ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR)); + + ppc->cur_ctrl |= port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + last = *data; + + outb(last, ppc->lpt_addr); + + while(count) + { + this = *data++; + count--; + + if (this == last) + { + ppc->cur_ctrl ^= data_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + } + else + { + outb(this, ppc->lpt_addr); + + last = this; + } + } + + ppc->cur_ctrl &= ~port_stb; + + outb(ppc->cur_ctrl, ppc->lpt_addr + 2); + + ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR)); + + break; + } + + case PPCMODE_EPP_BYTE : + { + while(count) + { + outb(*data++,ppc->lpt_addr + 4); + count--; + } + + ppc6_wait_for_fifo(ppc); + + break; + } + + case PPCMODE_EPP_WORD : + { + while(count > 1) + { + outw(*((u16 *)data),ppc->lpt_addr + 4); + data += 2; + count -= 2; + } + + while(count) + { + outb(*data++,ppc->lpt_addr + 4); + count--; + } + + ppc6_wait_for_fifo(ppc); + + break; + } + + case PPCMODE_EPP_DWORD : + { + while(count > 3) + { + outl(*((u32 *)data),ppc->lpt_addr + 4); + data += 4; + count -= 4; + } + + while(count) + { + outb(*data++,ppc->lpt_addr + 4); + count--; + } + + ppc6_wait_for_fifo(ppc); + + break; + } + } +} + +//*************************************************************************** + +static void ppc6_rd_port16_blk(PPC *ppc, u8 port, u8 *data, long length) +{ + length = length << 1; + + ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE)); + ppc6_wr_data_byte(ppc,(u8)length); + ppc6_wr_data_byte(ppc,(u8)(length >> 8)); + ppc6_wr_data_byte(ppc,0); + + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); + + ppc6_rd_data_blk(ppc, data, length); + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK)); +} + +//*************************************************************************** + +static u16 ppc6_rd_port16(PPC *ppc, u8 port) +{ + u16 data; + + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); + + data = ppc6_rd_data_byte(ppc); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ)); + + data += (u16)ppc6_rd_data_byte(ppc) << 8; + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16)); + + return(data); +} + +//*************************************************************************** + +static void ppc6_wr_port16(PPC *ppc, u8 port, u16 data) +{ + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, (u8)data); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, (u8)(data >> 8)); + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16)); +} + +//*************************************************************************** + +static void ppc6_wr_port16_blk(PPC *ppc, u8 port, u8 *data, long length) +{ + length = length << 1; + + ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE)); + ppc6_wr_data_byte(ppc,(u8)length); + ppc6_wr_data_byte(ppc,(u8)(length >> 8)); + ppc6_wr_data_byte(ppc,0); + + ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK)); + + ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE)); + + ppc6_wr_data_blk(ppc, data, length); + + ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK)); +} + +//*************************************************************************** + +static u8 ppc6_rd_eeprom_reg(PPC *ppc) +{ + ppc6_send_cmd(ppc, (REG_EEPROM | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc)); +} + +//*************************************************************************** + +static void ppc6_wr_eeprom_reg(PPC *ppc, u8 data) +{ + ppc6_send_cmd(ppc, (REG_EEPROM | ACCESS_REG | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, data); +} + +//*************************************************************************** + +static void ppc6_eeprom_start(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, EEPROM_EN); +} + +//*************************************************************************** + +static void ppc6_eeprom_end(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, 0); +} + +//*************************************************************************** + +static void ppc6_set_cs(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, (u8)(ppc6_rd_eeprom_reg(ppc) | EEPROM_CS)); +} + +//*************************************************************************** + +static void ppc6_reset_cs(PPC *ppc) +{ + ppc6_wr_eeprom_reg(ppc, (u8)(ppc6_rd_eeprom_reg(ppc) & ~EEPROM_CS)); +} + +//*************************************************************************** + +static u8 ppc6_rd_eeprom_bit(PPC *ppc) +{ + ppc6_send_cmd(ppc, (REG_STATUS | ACCESS_REG | ACCESS_READ)); + + if (ppc6_rd_data_byte(ppc) & STATUS_EEPROM_DO) + return(1); + else + return(0); +} + +//*************************************************************************** + +static void ppc6_eeprom_ready_wait(PPC *ppc) +{ + ppc6_set_cs(ppc); + + while(ppc6_rd_eeprom_bit(ppc)); + + ppc6_reset_cs(ppc); +} + +//*************************************************************************** + +static void ppc6_wr_eeprom_bit(PPC *ppc, u8 bit) +{ + u8 eereg; + + eereg = ppc6_rd_eeprom_reg(ppc); + + eereg &= ~(EEPROM_SK | EEPROM_DI); + + if (bit & 1) + eereg |= EEPROM_DI; + + ppc6_wr_eeprom_reg(ppc, eereg); + + eereg |= EEPROM_SK; + + ppc6_wr_eeprom_reg(ppc, eereg); + + eereg &= ~EEPROM_SK; + + ppc6_wr_eeprom_reg(ppc, eereg); +} + +//*************************************************************************** + +static u16 ppc6_eeprom_read(PPC *ppc, u8 addr) +{ + int i; + u16 data; + + ppc6_set_cs(ppc); + + ppc6_wr_eeprom_bit(ppc, 1); // Start bit + + ppc6_wr_eeprom_bit(ppc, 1); // opcode 10 (read) + ppc6_wr_eeprom_bit(ppc, 0); + + for(i=0; i<6; i++) + ppc6_wr_eeprom_bit(ppc, (u8)((addr >> (5 - i)) & 1)); + + data = 0; + + for(i=0; i<16; i++) + { + ppc6_wr_eeprom_bit(ppc,0); + + data = (data << 1) | ppc6_rd_eeprom_bit(ppc); + } + + ppc6_reset_cs(ppc); + + return(data); +} + +//*************************************************************************** + +static u8 ppc6_irq_test(PPC *ppc) +{ + ppc6_send_cmd(ppc,(REG_STATUS | ACCESS_REG | ACCESS_READ)); + + return(ppc6_rd_data_byte(ppc) & STATUS_IRQA); +} + +//*************************************************************************** + +static u8 ppc6_rd_extout(PPC *ppc) +{ + ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_READ)); + + return((ppc6_rd_data_byte(ppc) & 0xC0) >> 6); +} + +//*************************************************************************** + +static void ppc6_wr_extout(PPC *ppc, u8 regdata) +{ + ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE)); + + ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6)); +} + +//*************************************************************************** + +static int ppc6_open(PPC *ppc) +{ + int ret; + + ret = ppc6_select(ppc); + + if (ret == 0) + return(ret); + + ppc->ppc_flags &= ~fifo_wait; + + ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE)); + ppc6_wr_data_byte(ppc, RAMSIZE_128K); + + ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION)); + + if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C) + ppc->ppc_flags |= fifo_wait; + + return(ret); +} + +//*************************************************************************** + +static void ppc6_close(PPC *ppc) +{ + ppc6_deselect(ppc); +} + +//*************************************************************************** + diff -u --recursive --new-file v2.4.3/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.4.3/linux/drivers/block/ps2esdi.c Thu Oct 26 23:35:47 2000 +++ linux/drivers/block/ps2esdi.c Wed Apr 11 19:02:30 2001 @@ -89,8 +89,6 @@ static void ps2esdi_initial_reset_int_handler(u_int); static void ps2esdi_geometry_int_handler(u_int); -static void ps2esdi_continue_request(void); - static int ps2esdi_open(struct inode *inode, struct file *file); static int ps2esdi_release(struct inode *inode, struct file *file); @@ -469,29 +467,26 @@ DEVICE_NAME, CURRENT_DEV, MINOR(CURRENT->rq_dev), CURRENT->cmd, CURRENT->sector, - CURRENT->nr_sectors, CURRENT->buffer); + CURRENT->current_nr_sectors, CURRENT->buffer); #endif /* standard macro that ensures that requests are really on the list + sanity checks. */ INIT_REQUEST; - if (virt_to_bus(CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) { + if (virt_to_bus(CURRENT->buffer + CURRENT->current_nr_sectors * 512) > 16 * MB) { printk("%s: DMA above 16MB not supported\n", DEVICE_NAME); end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(q); - return; } /* check for above 16Mb dmas */ - if ((CURRENT_DEV < ps2esdi_drives) && - (CURRENT->sector + CURRENT->nr_sectors <= + else if ((CURRENT_DEV < ps2esdi_drives) && + (CURRENT->sector + CURRENT->current_nr_sectors <= ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects)) { #if 0 printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld\n", DEVICE_NAME, - CURRENT_DEV, MINOR(CURRENT->dev), + CURRENT_DEV, MINOR(CURRENT->rq_dev), CURRENT->cmd, CURRENT->sector, - CURRENT->nr_sectors); + CURRENT->current_nr_sectors); #endif @@ -500,21 +495,17 @@ #if 0 printk("%s: blocknumber : %d\n", DEVICE_NAME, block); #endif - count = CURRENT->nr_sectors; + count = CURRENT->current_nr_sectors; switch (CURRENT->cmd) { case READ: ps2esdi_readwrite(READ, CURRENT_DEV, block, count); - return; break; case WRITE: ps2esdi_readwrite(WRITE, CURRENT_DEV, block, count); - return; break; default: printk("%s: Unknown command\n", DEVICE_NAME); end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(q); break; } /* handle different commands */ } @@ -523,8 +514,6 @@ printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives, CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects); end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(q); } } /* main strategy routine */ @@ -570,8 +559,6 @@ u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; /* do some relevant arithmatic */ - CURRENT->current_nr_sectors = - (count < (2 * MAX_16BIT / SECT_SIZE)) ? count : (2 * MAX_16BIT / SECT_SIZE); track = block / ps2esdi_info[drive].sect; head = track % ps2esdi_info[drive].head; cylinder = track / ps2esdi_info[drive].head; @@ -590,13 +577,8 @@ /* send the command block to the controller */ if (ps2esdi_out_cmd_blk(cmd_blk)) { printk("%s: Controller failed\n", DEVICE_NAME); - if ((++CURRENT->errors) < MAX_RETRIES) - return do_ps2esdi_request(NULL); - else { + if ((++CURRENT->errors) >= MAX_RETRIES) end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); - } } /* check for failure to put out the command block */ else { @@ -680,7 +662,7 @@ buffer=(char *)virt_to_bus(buffer); #if 0 - printk("ps2esdi: b_wait: %p\n", CURRENT->bh->b_wait); + printk("ps2esdi: b_wait: %p\n", &CURRENT->bh->b_wait); #endif cli(); @@ -871,7 +853,9 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code) { + unsigned long flags; u_int status; + u_int ending; int i; switch (int_ret_code & 0x0f) { @@ -879,12 +863,14 @@ ps2esdi_prep_dma(CURRENT->buffer, CURRENT->current_nr_sectors, (CURRENT->cmd == READ) ? DMA_READ_16 : DMA_WRITE_16); outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; case INT_ATTN_ERROR: printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, int_ret_code); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = FAIL; break; case INT_CMD_COMPLETE: @@ -893,13 +879,10 @@ printk("%s: timeout reading status word\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(NULL); - else { - end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); - } + if ((++CURRENT->errors) >= MAX_RETRIES) + ending = FAIL; + else + ending = -1; break; } status = inw(ESDI_STT_INT); @@ -910,15 +893,16 @@ outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); #if 0 - printk("ps2esdi: cmd_complete b_wait: %p\n", CURRENT->bh->b_wait); + printk("ps2esdi: cmd_complete b_wait: %p\n", &CURRENT->bh->b_wait); #endif - ps2esdi_continue_request(); + ending = SUCCES; break; default: printk("%s: interrupt for unknown command %02X\n", DEVICE_NAME, status & 0x1f); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; } break; @@ -929,7 +913,7 @@ dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ps2esdi_continue_request(); + ending = SUCCES; break; case INT_CMD_WARNING: case INT_CMD_ABORT: @@ -939,22 +923,17 @@ dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(NULL); - else { - end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); - } + if ((++CURRENT->errors) >= MAX_RETRIES) + ending = FAIL; + else + ending = -1; break; case INT_CMD_BLK_ERR: dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - end_request(FAIL); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); + ending = FAIL; break; case INT_CMD_FORMAT: @@ -962,12 +941,14 @@ ,DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; case INT_RESET: /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ; outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; default: @@ -975,24 +956,16 @@ DEVICE_NAME, int_ret_code & 0xf); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); + ending = -1; break; } - -} /* handle interrupts */ - - -static void ps2esdi_continue_request(void) -{ - if (CURRENT->nr_sectors -= CURRENT->current_nr_sectors) { - CURRENT->buffer += CURRENT->current_nr_sectors * SECT_SIZE; - CURRENT->sector += CURRENT->current_nr_sectors; - do_ps2esdi_request(NULL); - } else { - end_request(SUCCES); - if (!QUEUE_EMPTY) - do_ps2esdi_request(NULL); + if(ending != -1) { + spin_lock_irqsave(io_request_lock, flags); + end_request(ending); + do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR)); + spin_unlock_irqrestore(io_request_lock, flags); } -} +} /* handle interrupts */ diff -u --recursive --new-file v2.4.3/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.4.3/linux/drivers/cdrom/sbpcd.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/cdrom/sbpcd.c Fri Apr 6 10:42:55 2001 @@ -350,7 +350,7 @@ #ifndef SBPCD_ISSUE #define SBPCD_ISSUE 1 -#endif SBPCD_ISSUE +#endif /* SBPCD_ISSUE */ #include <linux/module.h> @@ -420,7 +420,7 @@ #else #define SBPCD_CLI #define SBPCD_STI -#endif SBPCD_DIS_IRQ +#endif /* SBPCD_DIS_IRQ */ /*==========================================================================*/ /* * auto-probing address list @@ -478,9 +478,9 @@ 0x370, 0, /* Lasermate, CI-101P */ 0x290, 1, /* Soundblaster 16 */ 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ -#endif MODULE +#endif /* MODULE */ #endif -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ }; #else static int sbpcd[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */ @@ -570,7 +570,7 @@ (1<<DBG_TOC) | (1<<DBG_MUL) | (1<<DBG_UPC)); -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */ static int sbpro_type = SBPRO; @@ -622,7 +622,7 @@ #if FUTURE static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq); -#endif FUTURE +#endif /* FUTURE */ static int teac=SBP_TEAC_SPEED; static int buffers=SBP_BUFFER_FRAMES; @@ -647,7 +647,7 @@ #if OLD_BUSY static volatile u_char busy_data; static volatile u_char busy_audio; /* true semaphores would be safer */ -#endif OLD_BUSY +#endif /* OLD_BUSY */ static DECLARE_MUTEX(ioctl_read_sem); static u_long timeout; static volatile u_char timed_out_delay; @@ -664,7 +664,7 @@ static u_int maxtim_data= 9000; #else static u_int maxtim_data= 3000; -#endif LONG_TIMING +#endif /* LONG_TIMING */ #if DISTRIBUTION static int n_retries=6; #else @@ -729,7 +729,7 @@ u_char vol_ctrl2; char vol_chan3; u_char vol_ctrl3; -#endif 000 +#endif /*000 */ u_char volume_control; /* TEAC on/off bits */ u_char SubQ_ctl_adr; @@ -758,7 +758,7 @@ u_int TocEnt_address; #if SAFE_MIXED char has_data; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */ struct { @@ -808,7 +808,7 @@ #define MSG_LEVEL KERN_NOTICE #else #define MSG_LEVEL KERN_INFO -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ char buf[256]; va_list args; @@ -824,7 +824,7 @@ printk(buf); #if KLOGD_PAUSE sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ -#endif KLOGD_PAUSE +#endif /* KLOGD_PAUSE */ return; } /*==========================================================================*/ @@ -1148,7 +1148,7 @@ } j=i-response_count; if (j>0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); -#endif 000 +#endif /* 000 */ for (j=0;j<i;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]); msgbuf[j*3]=0; @@ -1400,7 +1400,7 @@ if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ #if 01 OUT(CDo_sel_i_d,1); -#endif 01 +#endif /* 01 */ if (teac==2) { if ((i=CDi_stat_loop_T()) == -1) break; @@ -1409,7 +1409,7 @@ { #if 0 OUT(CDo_sel_i_d,1); -#endif 0 +#endif /* 0 */ i=inb(CDi_status); } if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ @@ -1433,7 +1433,7 @@ l=1; msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n"); } -#endif TEST_FALSE_FF +#endif /* TEST_FALSE_FF */ } else infobuf[l++]=inb(CDi_data); i=inb(CDi_status); @@ -2028,7 +2028,7 @@ msg(DBG_TEA, "================CMDT_RESET given=================.\n"); sbp_sleep(3*HZ); } -#endif 1 +#endif /* 1 */ flush_status(); i=GetStatus(); if (i<0) return i; @@ -2349,7 +2349,7 @@ i=ResponseStatus(); #if 0 sbp_sleep(HZ); -#endif 0 +#endif /* 0 */ i=ResponseStatus(); } if (i<0) @@ -2694,7 +2694,7 @@ D_S[d].vol_ctrl2=0xFF; D_S[d].vol_chan3=3; D_S[d].vol_ctrl3=0xFF; -#endif 000 +#endif /* 000 */ D_S[d].diskstate_flags |= volume_bit; return (0); } @@ -2994,20 +2994,20 @@ int i; #if TEST_UPC int block, checksum; -#endif TEST_UPC +#endif /* TEST_UPC */ if (fam2_drive) return (0); /* not implemented yet */ if (famT_drive) return (0); /* not implemented yet */ if (famV_drive) return (0); /* not implemented yet */ #if 1 if (fam0_drive) return (0); /* but it should work */ -#endif 1 +#endif D_S[d].diskstate_flags &= ~upc_bit; #if TEST_UPC for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++) { -#endif TEST_UPC +#endif /* TEST_UPC */ clr_cmdbuf(); if (fam1_drive) { @@ -3016,7 +3016,7 @@ drvcmd[1]=(block>>16)&0xFF; drvcmd[2]=(block>>8)&0xFF; drvcmd[3]=block&0xFF; -#endif TEST_UPC +#endif /* TEST_UPC */ response_count=8; flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; } @@ -3027,7 +3027,7 @@ drvcmd[2]=(block>>16)&0xFF; drvcmd[3]=(block>>8)&0xFF; drvcmd[4]=block&0xFF; -#endif TEST_UPC +#endif /* TEST_UPC */ response_count=0; flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; } @@ -3058,12 +3058,12 @@ } #if TEST_UPC checksum=0; -#endif TEST_UPC +#endif /* TEST_UPC */ for (i=0;i<(fam1_drive?8:16);i++) { #if TEST_UPC checksum |= infobuf[i]; -#endif TEST_UPC +#endif /* TEST_UPC */ sprintf(&msgbuf[i*3], " %02X", infobuf[i]); } msgbuf[i*3]=0; @@ -3071,7 +3071,7 @@ #if TEST_UPC if ((checksum&0x7F)!=0) break; } -#endif TEST_UPC +#endif /* TEST_UPC */ D_S[d].UPC_ctl_adr=0; if (fam1_drive) i=0; else i=2; @@ -3256,7 +3256,7 @@ i=cmd_out(); /* which buffer to use? */ return (i); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ static void __init check_datarate(void) { @@ -3283,7 +3283,7 @@ datarate++; #if 1 if (datarate>0x6FFFFFFF) break; -#endif 00000 +#endif } while (!timed_out_delay); del_timer(&delay_timer); @@ -3299,7 +3299,7 @@ maxtim_data=datarate/100; #else maxtim_data=datarate/300; -#endif LONG_TIMING +#endif /* LONG_TIMING */ #if 0 msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data); #endif @@ -3453,7 +3453,7 @@ OUT(CDo_reset,0); sbp_sleep(6*HZ); OUT(CDo_enable,D_S[d].drv_sel); -#endif 0 +#endif drvcmd[0]=CMD2_READ_VER; response_count=12; flags_cmd_out=f_putcmd; @@ -3743,7 +3743,7 @@ OUT(port+3,save_port3); return (0); /* in any case - no real "function" at time */ } -#endif PATH_CHECK +#endif /* PATH_CHECK */ /*==========================================================================*/ /*==========================================================================*/ /* @@ -3850,7 +3850,7 @@ if (func2==tell_UPC) return (-1); #else return (0); -#endif 000 +#endif } /*==========================================================================*/ static int check_allowed2(u_char func1, u_char func2) @@ -3868,7 +3868,7 @@ } #else return (0); -#endif 000 +#endif } /*==========================================================================*/ static int check_allowed3(u_char func1, u_char func2) @@ -3902,7 +3902,7 @@ if (func1==audio_resume) return (-1); #else return (0); -#endif 000 +#endif } /*==========================================================================*/ static int seek_pos_audio_end(void) @@ -3914,7 +3914,7 @@ i=cc_Seek(i,0); return (i); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ static int ReadToC(void) { @@ -4152,7 +4152,7 @@ } return (0); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ /*==========================================================================*/ /* @@ -4250,7 +4250,7 @@ msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ cc_ModeSelect(CD_FRAMESIZE); cc_ModeSense(); D_S[d].mode=READ_M1; @@ -4260,7 +4260,7 @@ msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ cc_ModeSelect(CD_FRAMESIZE_RAW1); cc_ModeSense(); D_S[d].mode=READ_M2; @@ -4303,7 +4303,7 @@ if (famT_drive) RETURN_UP(-EINVAL); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL); i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio)); if (i) RETURN_UP(i); @@ -4328,7 +4328,7 @@ #if OLD_BUSY while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ busy_audio=1; -#endif OLD_BUSY +#endif /* OLD_BUSY */ error_flag=0; for (data_tries=5; data_tries>0; data_tries--) { @@ -4460,7 +4460,7 @@ i=cc_DriveReset(); /* ugly fix to prevent a hang */ #else i=cc_ReadError(); -#endif 0000 +#endif continue; } if (fam0L_drive) @@ -4515,7 +4515,7 @@ D_S[d].mode=READ_M1; #if OLD_BUSY busy_audio=0; -#endif OLD_BUSY +#endif /* OLD_BUSY */ if (data_tries == 0) { msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); @@ -4601,7 +4601,7 @@ msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].audio_state==audio_playing) { i=cc_Pause_Resume(1); @@ -4636,7 +4636,7 @@ msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].audio_state==audio_playing) { msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); @@ -4699,7 +4699,7 @@ msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ i=cc_Pause_Resume(1); D_S[d].audio_state=0; #if 0 @@ -4942,7 +4942,7 @@ #if OLD_BUSY while (busy_audio) sbp_sleep(HZ); /* wait a bit */ busy_data=1; -#endif OLD_BUSY +#endif /* OLD_BUSY */ if (D_S[i].audio_state==audio_playing) goto err_done; if (d!=i) switch_drive(i); @@ -4973,7 +4973,7 @@ i=prepare(0,0); /* at moment not really a hassle check, but ... */ if (i!=0) msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i); -#endif FUTURE +#endif /* FUTURE */ if (!st_spinning) cc_SpinUp(); @@ -4999,7 +4999,7 @@ { #if SAFE_MIXED D_S[d].has_data=2; /* is really a data disk */ -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -5014,7 +5014,7 @@ err_done: #if OLD_BUSY busy_data=0; -#endif OLD_BUSY +#endif /* OLD_BUSY */ #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -5373,17 +5373,17 @@ #if 0 if (!success) -#endif 0 +#endif do { if (fam0LV_drive) cc_ReadStatus(); #if 1 if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i); -#endif 1 +#endif i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ #if 1 if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i); -#endif 1 +#endif if (i<0) { msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", D_S[d].status_bits); @@ -5443,11 +5443,11 @@ msg(DBG_INF,"CD contains no data tracks.\n"); #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } #if SAFE_MIXED else if (D_S[d].has_data<1) D_S[d].has_data=1; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } if (!st_spinning) cc_SpinUp(); RETURN_UP(0); @@ -5485,7 +5485,7 @@ D_S[d].open_count=0; #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } } up(&ioctl_read_sem); @@ -5697,7 +5697,7 @@ int __init __SBPCD_INIT(void) #else int __init SBPCD_INIT(void) -#endif MODULE +#endif /* MODULE */ { char nbuff[16]; int i=0, j=0; @@ -5724,10 +5724,10 @@ msg(DBG_INF,"with your REAL address.\n"); msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n"); } -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */ -#endif MODULE +#endif /* MODULE */ for (port_index=0;port_index<NUM_PROBE;port_index+=2) { @@ -5745,7 +5745,7 @@ sbpcd_setup((char *)type); #if DISTRIBUTION msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type); -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ if (sbpcd[port_index+1]==2) { i=config_spea(); @@ -5753,7 +5753,7 @@ } #ifdef PATH_CHECK if (check_card(addr[1])) continue; -#endif PATH_CHECK +#endif /* PATH_CHECK */ i=check_drives(); msg(DBG_INI,"check_drives done.\n"); if (i>=0) break; /* drive found */ @@ -5766,7 +5766,7 @@ return -EIO; #else goto init_done; -#endif MODULE +#endif /* MODULE */ } if (port_index>0) @@ -5783,7 +5783,7 @@ switch_drive(j); #if 1 if (!famL_drive) cc_DriveReset(); -#endif 0 +#endif if (!st_spinning) cc_SpinUp(); D_S[j].sbp_first_frame = -1; /* First frame in buffer */ D_S[j].sbp_last_frame = -1; /* Last frame in buffer */ @@ -5794,7 +5794,7 @@ D_S[j].f_eject=0; #if EJECT if (!fam0_drive) D_S[j].f_eject=1; -#endif EJECT +#endif /* EJECT */ cc_ReadStatus(); i=ResponseStatus(); /* returns orig. status or p_busy_new */ if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */ @@ -5840,7 +5840,7 @@ #if SOUND_BASE OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */ OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */ -#endif SOUND_BASE +#endif /* SOUND_BASE */ if (devfs_register_blkdev(MAJOR_NR, major_name, &cdrom_fops) != 0) { @@ -5849,7 +5849,7 @@ return -EIO; #else goto init_done; -#endif MODULE +#endif /* MODULE */ } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); #ifdef DONT_MERGE_REQUESTS @@ -5871,7 +5871,7 @@ switch_drive(j); #if SAFE_MIXED D_S[j].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ /* * allocate memory for the frame buffers */ @@ -5894,7 +5894,7 @@ } #ifdef MODULE msg(DBG_INF,"data buffer size: %d frames.\n",buffers); -#endif MODULE +#endif /* MODULE */ if (D_S[j].sbp_audsiz>0) { D_S[j].aud_buf=(u_char *) vmalloc(D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW); @@ -5934,15 +5934,15 @@ #if !(SBPCD_ISSUE-1) #ifdef CONFIG_SBPCD2 sbpcd2_init(); -#endif CONFIG_SBPCD2 +#endif /* CONFIG_SBPCD2 */ #ifdef CONFIG_SBPCD3 sbpcd3_init(); -#endif CONFIG_SBPCD3 +#endif /* CONFIG_SBPCD3 */ #ifdef CONFIG_SBPCD4 sbpcd4_init(); -#endif CONFIG_SBPCD4 -#endif !(SBPCD_ISSUE-1) -#endif MODULE +#endif /* CONFIG_SBPCD4 */ +#endif /* !(SBPCD_ISSUE-1) */ +#endif /* MODULE */ return 0; } /*==========================================================================*/ @@ -5981,7 +5981,7 @@ module_exit(sbpcd_exit); -#endif MODULE +#endif /* MODULE */ /*==========================================================================*/ /* * Check if the media has changed in the CD-ROM drive. @@ -6004,7 +6004,7 @@ D_S[d].diskstate_flags &= ~cd_size_bit; #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ return (1); } diff -u --recursive --new-file v2.4.3/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.3/linux/drivers/char/Makefile Tue Mar 6 19:44:34 2001 +++ linux/drivers/char/Makefile Fri Apr 13 20:31:32 2001 @@ -68,6 +68,23 @@ KEYBD = scan_keyb.o hp600_keyb.o CONSOLE = console.o endif + ifeq ($(CONFIG_SH_DMIDA),y) + # DMIDA does not connect the HD64465 PS/2 keyboard port + # but we allow for USB keyboards to be plugged in. + KEYMAP = defkeymap.o + KEYBD = # hd64465_keyb.o pc_keyb.o + CONSOLE = console.o + endif + ifeq ($(CONFIG_SH_EC3104),y) + KEYMAP = defkeymap.o + KEYBD = ec3104_keyb.o + CONSOLE = console.o + endif + ifeq ($(CONFIG_SH_DREAMCAST),y) + KEYMAP = defkeymap.o + KEYBD = + CONSOLE = console.o + endif endif ifeq ($(CONFIG_DECSTATION),y) diff -u --recursive --new-file v2.4.3/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- v2.4.3/linux/drivers/char/agp/agpgart_fe.c Tue Mar 6 19:28:32 2001 +++ linux/drivers/char/agp/agpgart_fe.c Wed Apr 11 19:02:30 2001 @@ -879,7 +879,7 @@ return -ENOMEM; } if (copy_from_user(segment, (void *) reserve.seg_list, - GFP_KERNEL)) { + sizeof(agp_segment) * reserve.seg_count)) { kfree(segment); return -EFAULT; } diff -u --recursive --new-file v2.4.3/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.4.3/linux/drivers/char/cyclades.c Wed Nov 15 00:41:03 2000 +++ linux/drivers/char/cyclades.c Fri Apr 6 10:42:55 2001 @@ -209,7 +209,7 @@ * board type. * * Revision 1.36.4.30 1997/05/16 15:30:00 daniel - * Changes to suport new cycladesZ boards. + * Changes to support new cycladesZ boards. * * Revision 1.36.4.29 1997/05/12 11:30:00 daniel * Merge of Bentson's and Daniel's version 1.36.4.28. @@ -241,7 +241,7 @@ * varying too fast. * * Revision 1.36.4.27 1997/03/26 10:30:00 daniel - * Changed for suport linux versions 2.1.X. + * Changed for support linux versions 2.1.X. * Backward compatible with linux versions 2.0.X. * Corrected illegal use of filler field in * CH_CTRL struct. @@ -676,14 +676,6 @@ #include <linux/stat.h> #include <linux/proc_fs.h> - -#ifdef CONFIG_COBALT_27 -#include <asm/page.h> -#include <asm/pgtable.h> - -#define CACHED_TO_UNCACHED(x) (((unsigned long)(x) & \ - (unsigned long)0x1fffffff) + KSEG1) -#endif #define cy_put_user put_user diff -u --recursive --new-file v2.4.3/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c --- v2.4.3/linux/drivers/char/drm/ffb_drv.c Sun Mar 25 18:14:20 2001 +++ linux/drivers/char/drm/ffb_drv.c Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: ffb_drv.c,v 1.9 2001/03/23 07:58:39 davem Exp $ +/* $Id: ffb_drv.c,v 1.12 2001/04/14 01:12:03 davem Exp $ * ffb_drv.c: Creator/Creator3D direct rendering driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -6,8 +6,10 @@ #include "drmP.h" +#include <linux/config.h> #include <linux/sched.h> #include <linux/smp_lock.h> +#include <asm/shmparam.h> #include <asm/oplib.h> #include <asm/upa.h> @@ -34,6 +36,7 @@ static int ffb_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); static int ffb_mmap(struct file *filp, struct vm_area_struct *vma); +static unsigned long ffb_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); /* From ffb_context.c */ extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long); @@ -46,15 +49,16 @@ extern int ffb_context_switch(drm_device_t *, int, int); static struct file_operations ffb_fops = { - owner: THIS_MODULE, - open: ffb_open, - flush: drm_flush, - release: ffb_release, - ioctl: ffb_ioctl, - mmap: ffb_mmap, - read: drm_read, - fasync: drm_fasync, - poll: drm_poll, + owner: THIS_MODULE, + open: ffb_open, + flush: drm_flush, + release: ffb_release, + ioctl: ffb_ioctl, + mmap: ffb_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, + get_unmapped_area: ffb_get_unmapped_area, }; /* This is just a template, we make a new copy for each FFB @@ -770,45 +774,6 @@ return 0; } -static void align_fb_mapping(struct vm_area_struct *vma) -{ - unsigned long j, alignment; - - j = vma->vm_end - vma->vm_start; - for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3) - if (j >= alignment) - break; - if (alignment > PAGE_SIZE) { - j = alignment; - alignment = j - (vma->vm_start & (j - 1)); - if (alignment != j) { - struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start); - - if (!vmm || vmm->vm_start >= vma->vm_end + alignment) { - vma->vm_start += alignment; - vma->vm_end += alignment; - } - } - } -} - -/* The problem here is, due to virtual cache aliasing, - * we must make sure the shared memory area lands in the - * same dcache line for both the kernel and all drm clients. - */ -static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt) -{ - kvirt &= PAGE_SIZE; - if ((vma->vm_start & PAGE_SIZE) != kvirt) { - struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start); - - if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) { - vma->vm_start += PAGE_SIZE; - vma->vm_end += PAGE_SIZE; - } - } -} - extern struct vm_operations_struct drm_vm_ops; extern struct vm_operations_struct drm_vm_shm_ops; extern struct vm_operations_struct drm_vm_shm_lock_ops; @@ -868,7 +833,6 @@ switch (map->type) { case _DRM_FRAME_BUFFER: - align_fb_mapping(vma); /* FALLTHROUGH */ case _DRM_REGISTERS: @@ -887,7 +851,6 @@ vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: - align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock); if (map->flags & _DRM_CONTAINS_LOCK) vma->vm_ops = &drm_vm_shm_lock_ops; else { @@ -909,6 +872,69 @@ vma->vm_file = filp; /* Needed for drm_vm_open() */ drm_vm_open(vma); return 0; +} + +static drm_map_t *ffb_find_map(struct file *filp, unsigned long off) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + drm_map_t *map; + int i; + + if (!priv || (dev = priv->dev) == NULL) + return NULL; + + for (i = 0; i < dev->map_count; i++) { + unsigned long uoff; + + map = dev->maplist[i]; + + /* Ok, a little hack to make 32-bit apps work. */ + uoff = (map->offset & 0xffffffff); + if (uoff == off) + return map; + } + return NULL; +} + +static unsigned long ffb_get_unmapped_area(struct file *filp, unsigned long hint, unsigned long len, unsigned long pgoff, unsigned long flags) +{ + drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT); + unsigned long addr = -ENOMEM; + + if (!map) + return get_unmapped_area(NULL, hint, len, pgoff, flags); + + if (map->type == _DRM_FRAME_BUFFER || + map->type == _DRM_REGISTERS) { +#ifdef HAVE_ARCH_FB_UNMAPPED_AREA + addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags); +#else + addr = get_unmapped_area(NULL, hint, len, pgoff, flags); +#endif + } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) { + unsigned long slack = SHMLBA - PAGE_SIZE; + + addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags); + if (!(addr & ~PAGE_MASK)) { + unsigned long kvirt = (unsigned long) map->handle; + + if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { + unsigned long koff, aoff; + + koff = kvirt & (SHMLBA - 1); + aoff = addr & (SHMLBA - 1); + if (koff < aoff) + koff += SHMLBA; + + addr += (koff - aoff); + } + } + } else { + addr = get_unmapped_area(NULL, hint, len, pgoff, flags); + } + + return addr; } module_init(ffb_init); diff -u --recursive --new-file v2.4.3/linux/drivers/char/ec3104_keyb.c linux/drivers/char/ec3104_keyb.c --- v2.4.3/linux/drivers/char/ec3104_keyb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ec3104_keyb.c Fri Apr 13 20:31:32 2001 @@ -0,0 +1,461 @@ +/* + * linux/drivers/char/ec3104_keyb.c + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + * based on linux/drivers/char/pc_keyb.c, which had the following comments: + * + * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 + * See keyboard.c for the whole history. + * + * Major cleanup by Martin Mares, May 1997 + * + * Combined the keyboard and PS/2 mouse handling into one file, + * because they share the same hardware. + * Johan Myreen <jem@iki.fi> 1998-10-08. + * + * Code fixes to handle mouse ACKs properly. + * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. + */ +/* EC3104 note: + * This code was written without any documentation about the EC3104 chip. While + * I hope I got most of the basic functionality right, the register names I use + * are most likely completely different from those in the chip documentation. + * + * If you have any further information about the EC3104, please tell me + * (prumpf@tux.org). + */ + +#include <linux/config.h> + +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/signal.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/delay.h> +#include <linux/random.h> +#include <linux/poll.h> +#include <linux/miscdevice.h> +#include <linux/malloc.h> +#include <linux/kbd_kern.h> +#include <linux/smp_lock.h> + +#include <asm/keyboard.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/ec3104.h> + +#include <asm/io.h> + +/* Some configuration switches are present in the include file... */ + +#include <linux/pc_keyb.h> + +#define MSR_CTS 0x10 +#define MCR_RTS 0x02 +#define LSR_DR 0x01 +#define LSR_BOTH_EMPTY 0x60 + +static struct e5_struct { + u8 packet[8]; + int pos; + int length; + + u8 cached_mcr; + u8 last_msr; +} ec3104_keyb; + +/* Simple translation table for the SysRq keys */ + + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char ec3104_kbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +static void kbd_write_command_w(int data); +static void kbd_write_output_w(int data); +#ifdef CONFIG_PSMOUSE +static void aux_write_ack(int val); +static void __aux_write_ack(int val); +#endif + +static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); + +/* used only by send_data - set by keyboard_interrupt */ +static volatile unsigned char reply_expected; +static volatile unsigned char acknowledge; +static volatile unsigned char resend; + + +int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + return 0; +} + +int ec3104_kbd_getkeycode(unsigned int scancode) +{ + return 0; +} + + +/* yes, it probably would be faster to use an array. I don't care. */ + +static inline unsigned char ec3104_scan2key(unsigned char scancode) +{ + switch (scancode) { + case 1: /* '`' */ + return 41; + + case 2 ... 27: + return scancode; + + case 28: /* '\\' */ + return 43; + + case 29 ... 39: + return scancode + 1; + + case 40: /* '\r' */ + return 28; + + case 41 ... 50: + return scancode + 3; + + case 51: /* ' ' */ + return 57; + + case 52: /* escape */ + return 1; + + case 54: /* insert/delete (labelled delete) */ + /* this should arguably be 110, but I'd like to have ctrl-alt-del + * working with a standard keymap */ + return 111; + + case 55: /* left */ + return 105; + case 56: /* home */ + return 102; + case 57: /* end */ + return 107; + case 58: /* up */ + return 103; + case 59: /* down */ + return 108; + case 60: /* pgup */ + return 104; + case 61: /* pgdown */ + return 109; + case 62: /* right */ + return 106; + + case 79 ... 88: /* f1 - f10 */ + return scancode - 20; + + case 89 ... 90: /* f11 - f12 */ + return scancode - 2; + + case 91: /* left shift */ + return 42; + + case 92: /* right shift */ + return 54; + + case 93: /* left alt */ + return 56; + case 94: /* right alt */ + return 100; + case 95: /* left ctrl */ + return 29; + case 96: /* right ctrl */ + return 97; + + case 97: /* caps lock */ + return 58; + case 102: /* left windows */ + return 125; + case 103: /* right windows */ + return 126; + + case 106: /* Fn */ + /* this is wrong. */ + return 84; + + default: + return 0; + } +} + +int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + scancode &= 0x7f; + + *keycode = ec3104_scan2key(scancode); + + return 1; +} + +char ec3104_kbd_unexpected_up(unsigned char keycode) +{ + return 0200; +} + +static inline void handle_keyboard_event(unsigned char scancode) +{ +#ifdef CONFIG_VT + handle_scancode(scancode, !(scancode & 0x80)); +#endif + tasklet_schedule(&keyboard_tasklet); +} + +void ec3104_kbd_leds(unsigned char leds) +{ +} + +static u8 e5_checksum(u8 *packet, int count) +{ + int i; + u8 sum = 0; + + for (i=0; i<count; i++) + sum ^= packet[i]; + + if (sum & 0x80) + sum ^= 0xc0; + + return sum; +} + +static void e5_wait_for_cts(struct e5_struct *k) +{ + u8 msr; + + do { + msr = ctrl_inb(EC3104_SER4_MSR); + } while (!(msr & MSR_CTS)); +} + + +static void e5_send_byte(u8 byte, struct e5_struct *k) +{ + u8 status; + + do { + status = ctrl_inb(EC3104_SER4_LSR); + } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); + + printk("<%02x>", byte); + + ctrl_outb(byte, EC3104_SER4_DATA); + + do { + status = ctrl_inb(EC3104_SER4_LSR); + } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); + +} + +static int e5_send_packet(u8 *packet, int count, struct e5_struct *k) +{ + int i; + + disable_irq(EC3104_IRQ_SER4); + + if (k->cached_mcr & MCR_RTS) { + printk("e5_send_packet: too slow\n"); + enable_irq(EC3104_IRQ_SER4); + return -EAGAIN; + } + + k->cached_mcr |= MCR_RTS; + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + + e5_wait_for_cts(k); + + printk("p: "); + + for(i=0; i<count; i++) + e5_send_byte(packet[i], k); + + e5_send_byte(e5_checksum(packet, count), k); + + printk("\n"); + + udelay(1500); + + k->cached_mcr &= ~MCR_RTS; + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + + set_current_state(TASK_UNINTERRUPTIBLE); + + + + enable_irq(EC3104_IRQ_SER4); + + + + return 0; +} + +/* + * E5 packets we know about: + * E5->host 0x80 0x05 <checksum> - resend packet + * host->E5 0x83 0x43 <contrast> - set LCD contrast + * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight + * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2 + * E5->host 0x88 <scancode> <checksum> - key press + */ + +static void e5_receive(struct e5_struct *k) +{ + k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA); + + if (k->pos == 1) { + switch(k->packet[0]) { + case 0x80: + k->length = 3; + break; + + case 0x87: /* PS2 ext */ + k->length = 6; + break; + + case 0x88: /* keyboard */ + k->length = 3; + break; + + default: + k->length = 1; + printk(KERN_WARNING "unknown E5 packet %02x\n", + k->packet[0]); + } + } + + if (k->pos == k->length) { + int i; + + if (e5_checksum(k->packet, k->length) != 0) + printk(KERN_WARNING "E5: wrong checksum\n"); + +#if 0 + printk("E5 packet ["); + for(i=0; i<k->length; i++) { + printk("%02x ", k->packet[i]); + } + + printk("(%02x)]\n", e5_checksum(k->packet, k->length-1)); +#endif + + switch(k->packet[0]) { + case 0x80: + case 0x88: + handle_keyboard_event(k->packet[1]); + break; + } + + k->pos = k->length = 0; + } +} + +static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs) +{ + struct e5_struct *k = &ec3104_keyb; + u8 msr, lsr; + + kbd_pt_regs = regs; + + msr = ctrl_inb(EC3104_SER4_MSR); + + if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) { + if (k->cached_mcr & MCR_RTS) + printk("confused: RTS already high\n"); + /* CTS went high. Send RTS. */ + k->cached_mcr |= MCR_RTS; + + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) { + /* CTS went low. */ + if (!(k->cached_mcr & MCR_RTS)) + printk("confused: RTS already low\n"); + + k->cached_mcr &= ~MCR_RTS; + + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + } + + k->last_msr = msr; + + lsr = ctrl_inb(EC3104_SER4_LSR); + + if (lsr & LSR_DR) + e5_receive(k); +} + +static void ec3104_keyb_clear_state(void) +{ + struct e5_struct *k = &ec3104_keyb; + u8 msr, lsr; + + /* we want CTS to be low */ + k->last_msr = 0; + + for (;;) { + schedule_timeout(HZ/10); + + msr = ctrl_inb(EC3104_SER4_MSR); + + lsr = ctrl_inb(EC3104_SER4_LSR); + + if (lsr & LSR_DR) { + e5_receive(k); + continue; + } + + if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) { + if (k->cached_mcr & MCR_RTS) + printk("confused: RTS already high\n"); + /* CTS went high. Send RTS. */ + k->cached_mcr |= MCR_RTS; + + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) { + /* CTS went low. */ + if (!(k->cached_mcr & MCR_RTS)) + printk("confused: RTS already low\n"); + + k->cached_mcr &= ~MCR_RTS; + + ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); + } else + break; + + k->last_msr = msr; + + continue; + } +} + +void __init ec3104_kbd_init_hw(void) +{ + ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR); + ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR); + + ec3104_keyb_clear_state(); + + /* Ok, finally allocate the IRQ, and off we go.. */ + request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL); +} diff -u --recursive --new-file v2.4.3/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.4.3/linux/drivers/char/epca.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/char/epca.c Fri Apr 13 20:26:07 2001 @@ -769,7 +769,7 @@ globalwinon(ch); /* ----------------------------------------------------------------- - Anding against size will wrap the pointer back to its begining + Anding against size will wrap the pointer back to its beginning position if it is necessary. This will only work if size is a power of 2 which should always be the case. Size is determined by the cards on board FEP/OS. @@ -789,7 +789,7 @@ tail = bc->tout; /* ------------------------------------------------------------------ - Anding against size will wrap the pointer back to its begining + Anding against size will wrap the pointer back to its beginning position if it is necessary. This will only work if size is a power of 2 which should always be the case. Size is determined by the cards on board FEP/OS. @@ -818,7 +818,7 @@ tail head The above diagram shows that buffer locations 2,3,4,5 and 6 have - data to be transmited, while head points at the next empty + data to be transmitted, while head points at the next empty location. To calculate how much space is available first we have to determine if the head pointer (tin) has wrapped. To do this compare the head pointer to the tail pointer, If head is equal @@ -827,9 +827,9 @@ that value from the buffers size. A one is subtracted from the new value to indicate how much space is available between the head pointer and end of buffer; as well as the space between the - begining of the buffer and the tail. If the head is not greater + beginning of the buffer and the tail. If the head is not greater or equal to the tail this indicates that the head has wrapped - around to the begining of the buffer. To calculate the space + around to the beginning of the buffer. To calculate the space available in this case simply subtract head from tail. This new value minus one represents the space available betwwen the head and tail pointers. In this example head (7) is greater than tail (2) @@ -849,7 +849,7 @@ head tail The above diagram shows that buffer locations 7,8,9,0 and 1 have - data to be transmited, while head points at the next empty + data to be transmitted, while head points at the next empty location. To find the space available we compare head to tail. If head is not equal to, or greater than tail this indicates that head has wrapped around. In this case head (2) is not equal to, or @@ -1339,7 +1339,7 @@ } /* --------------------------------------------------------------- - Allow someone else to be scheduled. We will occasionaly go + Allow someone else to be scheduled. We will occasionally go through this loop until one of the above conditions change. The below schedule call will allow other processes to enter and prevent this loop from hogging the cpu. @@ -1685,7 +1685,7 @@ the boards array is correct. This could be wrong if the card in question is PCI (And therefore has no ports entry in the boards structure.) The rest of the - information will be valid for PCI because the begining + information will be valid for PCI because the beginning of pc_init scans for PCI and determines i/o and base memory addresses. I am not sure if it is possible to read the number of ports supported by the card prior to @@ -1937,7 +1937,7 @@ /* ------------------------------------------------------------- This call is made by the user via. the ioctl call DIGI_INIT. - It is resposible for setting up all the card specific stuff. + It is responsible for setting up all the card specific stuff. ---------------------------------------------------------------- */ bd = &boards[crd]; diff -u --recursive --new-file v2.4.3/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.4.3/linux/drivers/char/esp.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/esp.c Fri Apr 6 10:42:55 2001 @@ -1907,7 +1907,7 @@ return get_lsr_info(info, (unsigned int *) arg); case TIOCSERSWILD: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; return 0; diff -u --recursive --new-file v2.4.3/linux/drivers/char/ftape/zftape/zftape-vtbl.c linux/drivers/char/ftape/zftape/zftape-vtbl.c --- v2.4.3/linux/drivers/char/ftape/zftape/zftape-vtbl.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/ftape/zftape/zftape-vtbl.c Fri Apr 6 10:42:55 2001 @@ -431,7 +431,7 @@ /* this functions translates the failed_sector_log, misused as * EOF-marker list, into a virtual volume table. The table mustn't be * written to tape, because this would occupy the first data segment, - * which should be the volume table, but is actualy the first segment + * which should be the volume table, but is actually the first segment * that is filled with data (when using standard ftape). We assume, * that we get a non-empty failed_sector_log. */ diff -u --recursive --new-file v2.4.3/linux/drivers/char/hp600_keyb.c linux/drivers/char/hp600_keyb.c --- v2.4.3/linux/drivers/char/hp600_keyb.c Fri Sep 22 14:21:17 2000 +++ linux/drivers/char/hp600_keyb.c Wed Apr 11 21:24:52 2001 @@ -1,13 +1,17 @@ /* - * $Id: hp600_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * $Id$ * Copyright (C) 2000 YAEGASHI Takeshi - * HP600 keyboard scan routine and translate table + * HP600 keyboard scan routine and translation table + * Copyright (C) 2000 Niibe Yutaka + * HP620 keyboard translation table */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/init.h> -#include <linux/delay.h> + +#include <asm/machvec.h> +#include <asm/delay.h> #include <asm/io.h> #include "scan_keyb.h" @@ -17,55 +21,119 @@ #define PFDR 0xa400012a #define PGDR 0xa400012c #define PHDR 0xa400012e +#define PJDR 0xa4000130 +#define PKDR 0xa4000132 +#define PLDR 0xa4000134 + +static const unsigned char hp620_japanese_table[] = { + /* PTD1 */ + 0x0a, 0x0b, 0x0c, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + /* PTD5 */ + 0x18, 0x19, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + /* PTD7 */ + 0x26, 0x1a, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + /* PTE0 */ + 0x27, 0x1b, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + /* PTE1 */ + 0x35, 0x28, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x3a, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x34, + /* PTE3 */ + 0x48, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2d, 0x2e, 0x7b, 0x30, 0x31, 0x32, 0x33, + /* PTE6 */ + 0x4b, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2c, 0x38, 0x00, 0x39, 0x79, 0x7d, 0x73, + /* PTE7 */ + 0x41, 0x42, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, + /* **** */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; -static const unsigned char hp690_japanese_table[]={ - 0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x70, 0x3a, - 0x3f, 0x3e, 0x40, 0x41, 0x42, 0x3d, 0x3c, 0x3b, - - 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35, - 0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x50, - 0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, +static const unsigned char hp680_japanese_table[] = { + /* PTD1 */ + 0x3a, 0x70, 0x29, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3b, 0x3c, 0x3d, 0x42, 0x41, 0x40, 0x3e, 0x3f, + /* PTD5 */ + 0x35, 0x28, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2d, 0x2e, 0x2f, 0x34, 0x33, 0x32, 0x30, 0x31, + /* PTD7 */ + 0x50, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x38, 0x7b, + /* PTE0 */ + 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x39, 0x53, 0x73, 0xf9, 0x00, 0x00, + /* PTE1 */ + 0x27, 0x1b, 0x2b, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x1f, 0x20, 0x21, 0x26, 0x25, 0x24, 0x22, 0x23, + /* PTE3 */ + 0x48, 0x7d, 0x36, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* PTE6 */ + 0x19, 0x1a, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x12, 0x13, 0x18, 0x17, 0x16, 0x14, 0x15, + /* PTE7 */ + 0x0b, 0x0c, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x05, 0x0a, 0x09, 0x08, 0x06, 0x07, + /* **** */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf9, 0x73, 0x53, 0x39, 0x00, 0x1d, - - 0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x1b, 0x27, - 0x23, 0x22, 0x24, 0x25, 0x26, 0x21, 0x20, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; - 0x00, 0x00, 0x00, 0x0f, 0x00, 0x36, 0x7d, 0x48, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x1a, 0x19, - 0x15, 0x14, 0x16, 0x17, 0x18, 0x13, 0x12, 0x11, +static int hp620_japanese_scan_kbd(unsigned char *s) +{ + int i; + unsigned char matrix_switch[] = { + 0xfd, 0xff, /* PTD1 */ + 0xdf, 0xff, /* PTD5 */ + 0x7f, 0xff, /* PTD7 */ + 0xff, 0xfe, /* PTE0 */ + 0xff, 0xfd, /* PTE1 */ + 0xff, 0xf7, /* PTE3 */ + 0xff, 0xbf, /* PTE6 */ + 0xff, 0x7f, /* PTE7 */ + }, *t=matrix_switch; - 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x0c, 0x0b, - 0x07, 0x06, 0x08, 0x09, 0x0a, 0x05, 0x04, 0x03, + for(i=0; i<8; i++) { + ctrl_outb(*t++, PDDR); + ctrl_outb(*t++, PEDR); + udelay(50); + *s++=ctrl_inb(PCDR); + *s++=ctrl_inb(PFDR); + } - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; + ctrl_outb(0xff, PDDR); + ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PGDR); + *s++=ctrl_inb(PHDR); -static const unsigned char hp690_switch[]= { - 0xfd, 0xff, - 0xdf, 0xff, - 0x7f, 0xff, - 0xff, 0xfe, - 0xff, 0xfd, - 0xff, 0xf7, - 0xff, 0xbf, - 0xff, 0x7f, -}; + return 0; +} -static void hp690_japanese_scan_kbd(unsigned char *s) +static int hp680_japanese_scan_kbd(unsigned char *s) { int i; - unsigned const char *t=hp690_switch; + unsigned char matrix_switch[] = { + 0xfd, 0xff, /* PTD1 */ + 0xdf, 0xff, /* PTD5 */ + 0x7f, 0xff, /* PTD7 */ + 0xff, 0xfe, /* PTE0 */ + 0xff, 0xfd, /* PTE1 */ + 0xff, 0xf7, /* PTE3 */ + 0xff, 0xbf, /* PTE6 */ + 0xff, 0x7f, /* PTE7 */ + }, *t=matrix_switch; - for(i=0; i<9; i++) { + for(i=0; i<8; i++) { ctrl_outb(*t++, PDDR); ctrl_outb(*t++, PEDR); *s++=ctrl_inb(PCDR); @@ -77,18 +145,25 @@ *s++=ctrl_inb(PGDR); *s++=ctrl_inb(PHDR); + + return 0; } void __init hp600_kbd_init_hw(void) { scan_kbd_init(); - register_scan_keyboard(hp690_japanese_scan_kbd, - hp690_japanese_table, 18); + + if (MACH_HP620) + register_scan_keyboard(hp620_japanese_scan_kbd, + hp620_japanese_table, 18); + else if (MACH_HP680 || MACH_HP690) + register_scan_keyboard(hp680_japanese_scan_kbd, + hp680_japanese_table, 18); + printk(KERN_INFO "HP600 matrix scan keyboard registered\n"); } - /**************************************************************** HP Jornada 690(Japanese version) keyboard scan matrix @@ -102,7 +177,6 @@ PTE6 REC Q on/off BS @ P PTE7 REC 1 on/off ^ - 0 - PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0 PTD1 F5 F4 F6 F7 F8 F3 F2 F1 PTD5 N B M , . V C X @@ -129,3 +203,136 @@ L: 0x0c3c 0x26 F F IP F F IP IP F ****************************************************************/ + +/**************************************************************** +HP Jornada 620(Japanese version) keyboard scan matrix + + PTC7 PTC6 PTC5 PTC4 PTC3 PTC2 PTC1 PTC0 +PTD1 EREC BS Ctrl on/off - 0 9 +PTD5 EREC BS Ctrl on/off ^ P O +PTD7 EREC BS Ctrl on/off ] @ L +PTE0 EREC BS Ctrl on/off Han/Zen [ ; +PTE1 EREC BS Ctrl on/off Enter : / +PTE3 EREC BS Ctrl on/off Right Up +PTE6 EREC BS Ctrl on/off Down Left +PTE7 EREC BS Ctrl on/off F8 F7 + + PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0 +PTD1 8 7 6 5 4 3 2 1 +PTD5 I U Y T R E W Q +PTD7 K J H G F D S A +PTE0 ESC Tab Shift +PTE1 . V Caps Hira +PTE3 , M N B Muhen C X +PTE6 _ \ Henkan Space Alt Z +PTE7 F6 F5 F4 F3 F2 F1 REC + + PTH0 +* on/off + + 7 6 5 4 3 2 1 0 +C: 0xffff 0xff IP IP IP IP IP IP IP IP +D: 0x4404 0xaf O F O F F F O F +E: 0x5045 0xff O O F F O F O O +F: 0xffff 0xff IP IP IP IP IP IP IP IP +G: 0xd5ff 0x00 IP O O O IP IP IP IP +H: 0x63ff 0xd1 O I F IP IP IP IP IP +J: 0x0004 0x02 F F F F F F O F +K: 0x0401 0xff F F O F F F F O +L: 0x0c00 0x20 F F IP F F F F F + +ADCSR: 0x08 +ADCR: 0x3f + + ****************************************************************/ + +/**************************************************************** +Japanese 109 keyboard scan code layout + + E02A- E1- +01 3B 3C 3D 3E 3F 40 41 42 43 44 57 58 E037 46 1045 + +29 02 03 04 05 06 07 08 09 0A 0B 0C 0D 7D 0E E052 E047 E049 45 E035 37 4A +0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C E053 E04F E051 47 48 49 4E +3A 1E 1F 20 21 22 23 24 25 26 27 28 2B 4B 4C 4D +2A 2C 2D 2E 2F 30 31 32 33 34 35 73 36 E048 4F 50 51 E0- +1D DB 38 7B 39 79 70 E038 DC DD E01D E04B E050 E04D 52 53 1C + +****************************************************************/ + +#if 0 +int __init hp620_keyboard_test(void) +{ + int i; + unsigned char s[18]; + unsigned long a, b, c, d; + + printk("PCCR: %04lx, PCDR: %02lx\n", + ctrl_inw(0xa4000104), ctrl_inb(0xa4000124)); + printk("PDCR: %04lx, PDDR: %02lx\n", + ctrl_inw(0xa4000106), ctrl_inb(0xa4000126)); + printk("PECR: %04lx, PEDR: %02lx\n", + ctrl_inw(0xa4000108), ctrl_inb(0xa4000128)); + printk("PFCR: %04lx, PFDR: %02lx\n", + ctrl_inw(0xa400010a), ctrl_inb(0xa400012a)); + printk("PGCR: %04lx, PGDR: %02lx\n", + ctrl_inw(0xa400010c), ctrl_inb(0xa400012c)); + printk("PHCR: %04lx, PHDR: %02lx\n", + ctrl_inw(0xa400010e), ctrl_inb(0xa400012e)); + printk("PJCR: %04lx, PJDR: %02lx\n", + ctrl_inw(0xa4000110), ctrl_inb(0xa4000130)); + printk("PKCR: %04lx, PKDR: %02lx\n", + ctrl_inw(0xa4000112), ctrl_inb(0xa4000132)); + printk("PLCR: %04lx, PLDR: %02lx\n", + ctrl_inw(0xa4000114), ctrl_inb(0xa4000134)); + + printk("ADCSR: %02lx, ADCR: %02lx\n", + ctrl_inb(0xa4000090), ctrl_inb(0xa4000092)); + + ctrl_inb(0xa4000004); + ctrl_inb(0xa4000006); + ctrl_inb(0xa4000008); + ctrl_outb(0, 0xa4000004); + ctrl_outb(0, 0xa4000006); + ctrl_outb(0, 0xa4000008); + ctrl_outb(0, 0xa4000090); + ctrl_outb(0x3b, 0xa4000090); + + while(1) { + hp620_japanese_scan_kbd(s); + for(i=0; i<18; i+=2) + printk("%02x%02x ", s[i], s[i+1]); + +#if 0 + ctrl_outb(~2, PJDR); + printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR)); + ctrl_outb(0xff, PJDR); + ctrl_outb(~1, PKDR); + printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR)); + ctrl_outb(~32, PKDR); + printk("%02lx%02lx ", ctrl_inb(PCDR), ctrl_inb(PFDR)); + ctrl_outb(0xff, PKDR); +#endif + + printk("%02lx%02lx%02lx%02lx ", a, b, c, d); + if(ctrl_inb(0xa4000090)&0x80) { + a=ctrl_inb(0xa4000080); + b=ctrl_inb(0xa4000084); + c=ctrl_inb(0xa4000088); + d=ctrl_inb(0xa400008c); + ctrl_outb(0x3b, 0xa4000090); + } + printk("%02lx%02lx%02lx ", + ctrl_inb(0xa4000004), + ctrl_inb(0xa4000006), + ctrl_inb(0xa4000008)); + + printk("\n"); + } + + return 0; +} +module_init(keyboard_probe); +#endif + + diff -u --recursive --new-file v2.4.3/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c --- v2.4.3/linux/drivers/char/i810_rng.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/char/i810_rng.c Thu Apr 12 12:15:25 2001 @@ -35,7 +35,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.9.5" +#define RNG_VERSION "0.9.6" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -81,26 +81,13 @@ #define RNG_ADDR 0xFFBC015F #define RNG_ADDR_LEN 3 -#define RNG_MAX_ENTROPY 8 /* max entropy h/w is capable of */ - #define RNG_MISCDEV_MINOR 183 /* official */ - -/* - * number of bytes required for a FIPS test. - * do not alter unless you really, I mean - * REALLY know what you are doing. - */ -#define RNG_FIPS_TEST_THRESHOLD 2500 - - /* * various RNG status variables. they are globals * as we only support a single RNG device */ -static int rng_hw_enabled; /* is the RNG h/w enabled? */ static void *rng_mem; /* token to our ioremap'd RNG register area */ -static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */ static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ @@ -113,18 +100,17 @@ return readb (rng_mem + RNG_HW_STATUS); } - -static inline void rng_hwstatus_set (u8 hw_status) +static inline u8 rng_hwstatus_set (u8 hw_status) { assert (rng_mem != NULL); writeb (hw_status, rng_mem + RNG_HW_STATUS); + return rng_hwstatus (); } static inline int rng_data_present (void) { assert (rng_mem != NULL); - assert (rng_hw_enabled > 0); return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; } @@ -133,65 +119,67 @@ static inline int rng_data_read (void) { assert (rng_mem != NULL); - assert (rng_hw_enabled > 0); return readb (rng_mem + RNG_DATA); } - /* - * rng_enable - enable or disable the RNG hardware + * rng_enable - enable the RNG hardware */ -static int rng_enable (int enable) + +static int rng_enable (void) { - int rc = 0, action = 0; + int rc = 0; u8 hw_status, new_status; DPRINTK ("ENTER\n"); hw_status = rng_hwstatus (); - if (enable) { - rng_hw_enabled++; - MOD_INC_USE_COUNT; - } else { - if (rng_hw_enabled) { - rng_hw_enabled--; - MOD_DEC_USE_COUNT; + if ((hw_status & RNG_ENABLED) == 0) { + new_status = rng_hwstatus_set (hw_status | RNG_ENABLED); + + if (new_status & RNG_ENABLED) + printk (KERN_INFO PFX "RNG h/w enabled\n"); + else { + printk (KERN_ERR PFX "Unable to enable the RNG\n"); + rc = -EIO; } } - if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) { - rng_hwstatus_set (hw_status | RNG_ENABLED); - action = 1; - } + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} - else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) { - rng_hwstatus_set (hw_status & ~RNG_ENABLED); - action = 2; - } +/* + * rng_disable - disable the RNG hardware + */ - new_status = rng_hwstatus (); +static void rng_disable(void) +{ + u8 hw_status, new_status; - if (action == 1) { - if (new_status & RNG_ENABLED) - printk (KERN_INFO PFX "RNG h/w enabled\n"); - else - printk (KERN_ERR PFX "Unable to enable the RNG\n"); - } else if (action == 2) { + DPRINTK ("ENTER\n"); + + hw_status = rng_hwstatus (); + + if (hw_status & RNG_ENABLED) { + new_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED); + if ((new_status & RNG_ENABLED) == 0) printk (KERN_INFO PFX "RNG h/w disabled\n"); - else + else { printk (KERN_ERR PFX "Unable to disable the RNG\n"); + } } - DPRINTK ("EXIT, returning %d\n", rc); - return rc; + DPRINTK ("EXIT\n"); } - static int rng_dev_open (struct inode *inode, struct file *filp) { + int rc; + if ((filp->f_mode & FMODE_READ) == 0) return -EINVAL; if (filp->f_mode & FMODE_WRITE) @@ -206,9 +194,10 @@ return -ERESTARTSYS; } - if (rng_enable (1)) { + rc = rng_enable (); + if (rc) { up (&rng_open_sem); - return -EIO; + return rc; } return 0; @@ -217,7 +206,7 @@ static int rng_dev_release (struct inode *inode, struct file *filp) { - rng_enable(0); + rng_disable (); up (&rng_open_sem); return 0; } @@ -315,8 +304,9 @@ } /* turn RNG h/w off, if it's on */ - rc = rng_enable (0); - if (rc) { + if (hw_status & RNG_ENABLED) + hw_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED); + if (hw_status & RNG_ENABLED) { printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); goto err_out_free_map; } @@ -381,8 +371,6 @@ printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); - rng_pdev = pdev; - DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -395,13 +383,9 @@ { DPRINTK ("ENTER\n"); - assert (rng_hw_enabled == 0); - misc_deregister (&rng_miscdev); iounmap (rng_mem); - - rng_pdev = NULL; DPRINTK ("EXIT\n"); } diff -u --recursive --new-file v2.4.3/linux/drivers/char/ip2.c linux/drivers/char/ip2.c --- v2.4.3/linux/drivers/char/ip2.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/char/ip2.c Thu Apr 12 12:16:35 2001 @@ -6,7 +6,6 @@ // __initdata should work as advertized // -#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> diff -u --recursive --new-file v2.4.3/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.4.3/linux/drivers/char/isicom.c Wed Dec 6 12:06:18 2000 +++ linux/drivers/char/isicom.c Fri Apr 6 10:42:55 2001 @@ -16,6 +16,10 @@ * * 10/6/99 sameer Merged the ISA and PCI drivers to * a new unified driver. + * 09/06/01 acme@conectiva.com.br use capable, not suser, do + * restore_flags on failure in + * isicom_send_break, verify put_user + * result * *********************************************************** * * To use this driver you also need the support package. You @@ -1354,13 +1358,13 @@ while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); if (!wait) { printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); - return; + goto out; } outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); outw((length & 0xff) << 8 | 0x00, base); outw((length & 0xff00), base); InterruptTheCard(base); - restore_flags(flags); +out: restore_flags(flags); } static int isicom_get_modem_info(struct isi_port * port, unsigned int * value) @@ -1375,8 +1379,7 @@ ((status & ISI_DSR) ? TIOCM_DSR : 0) | ((status & ISI_CTS) ? TIOCM_CTS : 0) | ((status & ISI_RI ) ? TIOCM_RI : 0); - put_user(info, (unsigned int *) value); - return 0; + return put_user(info, (unsigned int *) value); } static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd, @@ -1438,7 +1441,7 @@ reconfig_port = ((port->flags & ASYNC_SPD_MASK) != (newinfo.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((newinfo.close_delay != port->close_delay) || (newinfo.closing_wait != port->closing_wait) || ((newinfo.flags & ~ASYNC_USR_MASK) != diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in --- v2.4.3/linux/drivers/char/joystick/Config.in Tue Aug 22 11:55:47 2000 +++ linux/drivers/char/joystick/Config.in Wed Apr 11 19:02:30 2001 @@ -11,6 +11,7 @@ dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT + dep_tristate ' Crystal SoundFusion gameports' CONFIG_INPUT_CS461X $CONFIG_INPUT comment 'Gameport joysticks' dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT @@ -31,6 +32,7 @@ dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT + dep_tristate ' Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT dep_tristate ' I-Force/Serial controllers' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT dep_tristate ' I-Force/USB controllers' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/Makefile linux/drivers/char/joystick/Makefile --- v2.4.3/linux/drivers/char/joystick/Makefile Fri Dec 29 14:07:21 2000 +++ linux/drivers/char/joystick/Makefile Wed Apr 11 19:02:30 2001 @@ -35,11 +35,13 @@ obj-$(CONFIG_INPUT_NS558) += ns558.o gameport.o obj-$(CONFIG_INPUT_LIGHTNING) += lightning.o gameport.o obj-$(CONFIG_INPUT_PCIGAME) += pcigame.o gameport.o +obj-$(CONFIG_INPUT_CS461X) += cs461x.o gameport.o obj-$(CONFIG_INPUT_WARRIOR) += warrior.o serio.o obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o +obj-$(CONFIG_INPUT_STINGER) += stinger.o serio.o obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o serio.o obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/adi.c linux/drivers/char/joystick/adi.c --- v2.4.3/linux/drivers/char/joystick/adi.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/adi.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * $Id: adi.c,v 1.12 2000/06/03 20:18:52 vojtech Exp $ + * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -370,7 +370,8 @@ adi->cname[i] = adi_get_bits(adi, 8); adi->cname[i] = 0; - if (adi->length != (t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4)) { + t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4; + if (adi->length != t && adi->length != t + (t & 1)) { printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); adi->length = 0; return; diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/cobra.c linux/drivers/char/joystick/cobra.c --- v2.4.3/linux/drivers/char/joystick/cobra.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/cobra.c Wed Apr 11 19:02:30 2001 @@ -131,7 +131,7 @@ input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); for (j = 0; cobra_btn[j]; j++) - input_report_key(dev, cobra_btn[j], data[i] & (0x20 << i)); + input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); } diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/cs461x.c linux/drivers/char/joystick/cs461x.c --- v2.4.3/linux/drivers/char/joystick/cs461x.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/cs461x.c Wed Apr 11 19:02:30 2001 @@ -0,0 +1,331 @@ +/* + The all defines and part of code (such as cs461x_*) are + contributed from ALSA 0.5.8 sources. + See http://www.alsa-project.org/ for sources + + Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610 +*/ + +#include <asm/io.h> + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/gameport.h> +#include <linux/slab.h> +#include <linux/pci.h> + +MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>"); + +/* + These options are experimental + +#define COOKED_MODE +#define CS461X_FULL_MAP + +*/ + +#ifndef PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4610 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4612 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4615 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 +#endif + +/* Registers */ + +#define BA0_JSPT 0x00000480 +#define BA0_JSCTL 0x00000484 +#define BA0_JSC1 0x00000488 +#define BA0_JSC2 0x0000048C +#define BA0_JSIO 0x000004A0 + +/* Bits for JSPT */ + +#define JSPT_CAX 0x00000001 +#define JSPT_CAY 0x00000002 +#define JSPT_CBX 0x00000004 +#define JSPT_CBY 0x00000008 +#define JSPT_BA1 0x00000010 +#define JSPT_BA2 0x00000020 +#define JSPT_BB1 0x00000040 +#define JSPT_BB2 0x00000080 + +/* Bits for JSCTL */ + +#define JSCTL_SP_MASK 0x00000003 +#define JSCTL_SP_SLOW 0x00000000 +#define JSCTL_SP_MEDIUM_SLOW 0x00000001 +#define JSCTL_SP_MEDIUM_FAST 0x00000002 +#define JSCTL_SP_FAST 0x00000003 +#define JSCTL_ARE 0x00000004 + +/* Data register pairs masks */ + +#define JSC1_Y1V_MASK 0x0000FFFF +#define JSC1_X1V_MASK 0xFFFF0000 +#define JSC1_Y1V_SHIFT 0 +#define JSC1_X1V_SHIFT 16 +#define JSC2_Y2V_MASK 0x0000FFFF +#define JSC2_X2V_MASK 0xFFFF0000 +#define JSC2_Y2V_SHIFT 0 +#define JSC2_X2V_SHIFT 16 + +/* JS GPIO */ + +#define JSIO_DAX 0x00000001 +#define JSIO_DAY 0x00000002 +#define JSIO_DBX 0x00000004 +#define JSIO_DBY 0x00000008 +#define JSIO_AXOE 0x00000010 +#define JSIO_AYOE 0x00000020 +#define JSIO_BXOE 0x00000040 +#define JSIO_BYOE 0x00000080 + +/* + The card initialization code is obfuscated; the module cs461x + need to be loaded after ALSA modules initialized and something + played on the CS 4610 chip (see sources for details of CS4610 + initialization code from ALSA) +*/ + +/* Card specific definitions */ + +#define CS461X_BA0_SIZE 0x2000 +#define CS461X_BA1_DATA0_SIZE 0x3000 +#define CS461X_BA1_DATA1_SIZE 0x3800 +#define CS461X_BA1_PRG_SIZE 0x7000 +#define CS461X_BA1_REG_SIZE 0x0100 + +#define BA1_SP_DMEM0 0x00000000 +#define BA1_SP_DMEM1 0x00010000 +#define BA1_SP_PMEM 0x00020000 +#define BA1_SP_REG 0x00030000 + +#define BA1_DWORD_SIZE (13 * 1024 + 512) +#define BA1_MEMORY_COUNT 3 + +/* + Only one CS461x card is still suppoted; the code requires + redesign to avoid this limitatuion. +*/ + +static unsigned long ba0_addr; +static unsigned int *ba0; + +#ifdef CS461X_FULL_MAP +static unsigned long ba1_addr; +static union ba1_t { + struct { + unsigned int *data0; + unsigned int *data1; + unsigned int *pmem; + unsigned int *reg; + } name; + unsigned int *idx[4]; +} ba1; + +static void cs461x_poke(unsigned long reg, unsigned int val) +{ + ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val; +} + +static unsigned int cs461x_peek(unsigned long reg) +{ + return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]; +} + +#endif + +static void cs461x_pokeBA0(unsigned long reg, unsigned int val) +{ + ba0[reg >> 2] = val; +} + +static unsigned int cs461x_peekBA0(unsigned long reg) +{ + return ba0[reg >> 2]; +} + +static int cs461x_free(struct pci_dev *pdev) +{ + struct gameport *port = (struct gameport *)pdev->driver_data; + if(port){ + gameport_unregister_port(port); + kfree(port); + } + if (ba0) iounmap(ba0); +#ifdef CS461X_FULL_MAP + if (ba1.name.data0) iounmap(ba1.name.data0); + if (ba1.name.data1) iounmap(ba1.name.data1); + if (ba1.name.pmem) iounmap(ba1.name.pmem); + if (ba1.name.reg) iounmap(ba1.name.reg); +#endif + return 0; +} + +static void cs461x_gameport_trigger(struct gameport *gameport) +{ + cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); +} + +static unsigned char cs461x_gameport_read(struct gameport *gameport) +{ + return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io); +} + +static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + unsigned js1, js2, jst; + + js1 = cs461x_peekBA0(BA0_JSC1); + js2 = cs461x_peekBA0(BA0_JSC2); + jst = cs461x_peekBA0(BA0_JSPT); + + *buttons = (~jst >> 4) & 0x0F; + + axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF; + axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF; + axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF; + axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF; + + for(jst=0;jst<4;++jst) + if(axes[jst]==0xFFFF) axes[jst] = -1; + return 0; +} + +static int cs461x_gameport_open(struct gameport *gameport, int mode) +{ + switch (mode) { +#ifdef COOKED_MODE + case GAMEPORT_MODE_COOKED: + return 0; +#endif + case GAMEPORT_MODE_RAW: + return 0; + default: + return -1; + } + return 0; +} + +static struct pci_device_id cs461x_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */ + { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */ + { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl); + +static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + struct gameport* port; + + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n", + pdev->bus->number, pdev->devfn, rc); + return rc; + } + + ba0_addr = pci_resource_start(pdev, 0); +#ifdef CS461X_FULL_MAP + ba1_addr = pci_resource_start(pdev, 1); +#endif + if (ba0_addr == 0 || ba0_addr == ~0 +#ifdef CS461X_FULL_MAP + || ba1_addr == 0 || ba1_addr == ~0 +#endif + ) { + printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr); +#ifdef CS461X_FULL_MAP + printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr); +#endif + cs461x_free(pdev); + return -ENOMEM; + } + + ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE); +#ifdef CS461X_FULL_MAP + ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); + ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); + ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); + ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); + + if (ba0 == NULL || ba1.name.data0 == NULL || + ba1.name.data1 == NULL || ba1.name.pmem == NULL || + ba1.name.reg == NULL) { + cs461x_free(pdev); + return -ENOMEM; + } +#else + if (ba0 == NULL){ + cs461x_free(pdev); + return -ENOMEM; + } +#endif + printk(KERN_INFO "CS461x PCI: %lx[%d]\n", + ba0_addr, CS461X_BA0_SIZE); + + if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) { + printk(KERN_ERR "Memory allocation failed.\n"); + cs461x_free(pdev); + return -ENOMEM; + } + memset(port, 0, sizeof(struct gameport)); + + port->io = -1; + port->size = -1; + pdev->driver_data = port; + + port->open = cs461x_gameport_open; + port->read = cs461x_gameport_read; + port->trigger = cs461x_gameport_trigger; +#ifdef COOKED_MODE + port->cooked_read = cs461x_gameport_cooked_read; +#endif + + cs461x_pokeBA0(BA0_JSIO, 0xFF); // ? + cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); + + gameport_register_port(port); + + printk(KERN_INFO "gameport%d: CS461x PCI", port->number); + if (port->size > 1) printk(" size %d", port->size); + printk(" speed %d kHz\n", port->speed); + + return 0; +} + +static void __devexit cs461x_pci_remove(struct pci_dev *pdev) +{ + cs461x_free(pdev); +} + +static struct pci_driver cs461x_pci_driver = { + name: "PCI Gameport", + id_table: cs461x_pci_tbl, + probe: cs461x_pci_probe, + remove: cs461x_pci_remove, +}; + +int __init js_cs461x_init(void) +{ + return pci_module_init(&cs461x_pci_driver); +} + +void __exit js_cs461x_exit(void) +{ + pci_unregister_driver(&cs461x_pci_driver); +} + +module_init(js_cs461x_init); +module_exit(js_cs461x_exit); + diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/gamecon.c linux/drivers/char/joystick/gamecon.c --- v2.4.3/linux/drivers/char/joystick/gamecon.c Mon Aug 14 13:55:01 2000 +++ linux/drivers/char/joystick/gamecon.c Wed Apr 11 19:02:30 2001 @@ -1,11 +1,11 @@ /* - * $Id: gamecon.c,v 1.5 2000/06/25 09:56:58 vojtech Exp $ + * $Id: gamecon.c,v 1.11 2000/11/01 12:38:53 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * * Based on the work of: * Andree Borrmann John Dahlstrom - * David Kuder + * David Kuder Nathan Hand * * Sponsored by SuSE */ @@ -75,8 +75,7 @@ static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", - "Multisystem 2-button joystick", "N64 controller", "PSX pad", - "PSX NegCon", "PSX Analog contoller" }; + "Multisystem 2-button joystick", "N64 controller", "PSX controller" }; /* * N64 support. */ @@ -205,22 +204,30 @@ /* * PSX support - */ - -#define GC_PSX_DELAY 10 -#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */ + * + * See documentation at: + * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt + * http://www.gamesx.com/controldata/psxcont/psxcont.htm + * ftp://milano.usal.es/pablo/ + * + */ + +#define GC_PSX_DELAY 60 /* 60 usec */ +#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */ + +#define GC_PSX_MOUSE 1 /* Mouse */ +#define GC_PSX_NEGCON 2 /* NegCon */ +#define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */ +#define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */ +#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ + +#define GC_PSX_CLOCK 0x04 /* Pin 4 */ +#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_POWER 0xf8 /* Pins 5-9 */ +#define GC_PSX_SELECT 0x02 /* Pin 3 */ -#define GC_PSX_MOUSE 0x12 /* PSX Mouse */ -#define GC_PSX_NEGCON 0x23 /* NegCon pad */ -#define GC_PSX_NORMAL 0x41 /* Standard Digital controller */ -#define GC_PSX_ANALOGR 0x73 /* Analog controller in Red mode */ -#define GC_PSX_ANALOGG 0x53 /* Analog controller in Green mode */ - -#define GC_PSX_CLOCK 0x04 /* Pin 3 */ -#define GC_PSX_COMMAND 0x01 /* Pin 1 */ -#define GC_PSX_POWER 0xf8 /* Pins 5-9 */ -#define GC_PSX_SELECT 0x02 /* Pin 2 */ -#define GC_PSX_NOPOWER 0x04 +#define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */ +#define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */ static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, @@ -233,19 +240,17 @@ static int gc_psx_command(struct gc *gc, int b) { - int i, cmd, ret = 0; + int i, cmd, data = 0; - cmd = (b & 1) ? GC_PSX_COMMAND : 0; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++, b >>= 1) { + cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); udelay(GC_PSX_DELAY); - ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; - cmd = (b & 1) ? GC_PSX_COMMAND : 0; + data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(GC_PSX_DELAY); - b >>= 1; } - return ret; + return data; } /* @@ -253,29 +258,31 @@ * device identifier code. */ -static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data) +static int gc_psx_read_packet(struct gc *gc, unsigned char *data) { - int i, ret; + int i, id; unsigned long flags; + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ + udelay(GC_PSX_DELAY * 2); + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ + udelay(GC_PSX_DELAY * 2); + __save_flags(flags); __cli(); - parport_write_data(gc->pd->port, GC_PSX_POWER); - - parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(GC_PSX_DELAY * 2); gc_psx_command(gc, 0x01); /* Access pad */ - ret = gc_psx_command(gc, 0x42); /* Get device id */ - if (gc_psx_command(gc, 0) == 'Z') /* okay? */ - for (i = 0; i < length; i++) + id = gc_psx_command(gc, 0x42); /* Get device id */ + if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ + for (i = 0; i < GC_PSX_LEN(id) * 2; i++) data[i] = gc_psx_command(gc, 0); - else ret = -1; + } else id = 0; - parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER); __restore_flags(flags); - return ret; + parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); + + return GC_PSX_ID(id); } /* @@ -316,8 +323,8 @@ input_report_abs(dev + i, ABS_X, axes[0]); input_report_abs(dev + i, ABS_Y, -axes[1]); - input_report_abs(dev + i, ABS_HAT0X, !!(s & data[7]) - !!(s & data[6])); - input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - !!(s & data[4])); + input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7])); + input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); for (j = 0; j < 10; j++) input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); @@ -338,8 +345,8 @@ s = gc_status_bit[i]; if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { - input_report_abs(dev + i, ABS_X, !!(s & data[7]) - !!(s & data[6])); - input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - !!(s & data[4])); + input_report_abs(dev + i, ABS_X, ! - !(s & data[6]) - !(s & data[7])); + input_report_abs(dev + i, ABS_Y, ! - !(s & data[4]) - !(s & data[5])); } if (s & gc->pads[GC_NES]) @@ -365,8 +372,8 @@ s = gc_status_bit[i]; if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { - input_report_abs(dev + i, ABS_X, !!(s & data[3]) - !!(s & data[2])); - input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - !!(s & data[0])); + input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3])); + input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1])); input_report_key(dev + i, BTN_TRIGGER, s & data[4]); } @@ -385,37 +392,37 @@ if (gc->pads[GC_PSX] & gc_status_bit[i]) break; - switch (gc_psx_read_packet(gc, 6, data)) { + switch (gc_psx_read_packet(gc, data)) { + + case GC_PSX_RUMBLE: + + input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04); + input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02); + + case GC_PSX_NEGCON: + case GC_PSX_ANALOG: - case GC_PSX_ANALOGG: - for (j = 0; j < 4; j++) input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); - input_report_abs(dev + i, ABS_HAT0X, !!(data[0]&0x20) - !!(data[0]&0x80)); - input_report_abs(dev + i, ABS_HAT0Y, !!(data[0]&0x40) - !!(data[0]&0x10)); + input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); + input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i)); + input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); break; - case GC_PSX_ANALOGR: - - input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04); - input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02); - case GC_PSX_NORMAL: - case GC_PSX_NEGCON: - input_report_abs(dev + i, ABS_X, 128 + !!(data[0] & 0x20) * 127 - !!(data[0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !!(data[0] & 0x40) * 127 - !!(data[0] & 0x10) * 128); + input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i)); + input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); @@ -448,14 +455,12 @@ } } - - static struct gc __init *gc_probe(int *config) { struct gc *gc; struct parport *pp; - int i, j, psx, pbtn; - unsigned char data[2]; + int i, j, psx; + unsigned char data[32]; if (config[0] < 0) return NULL; @@ -545,44 +550,42 @@ case GC_PSX: - psx = gc_psx_read_packet(gc, 2, data); + psx = gc_psx_read_packet(gc, data); switch(psx) { case GC_PSX_NEGCON: - config[i + 1] += 1; case GC_PSX_NORMAL: - pbtn = 10; - break; + case GC_PSX_ANALOG: + case GC_PSX_RUMBLE: - case GC_PSX_ANALOGG: - case GC_PSX_ANALOGR: - config[i + 1] += 2; - pbtn = 12; for (j = 0; j < 6; j++) { psx = gc_psx_abs[j]; set_bit(psx, gc->dev[i].absbit); - gc->dev[i].absmin[psx] = 4; - gc->dev[i].absmax[psx] = 252; - gc->dev[i].absflat[psx] = 2; + if (j < 4) { + gc->dev[i].absmin[psx] = 4; + gc->dev[i].absmax[psx] = 252; + gc->dev[i].absflat[psx] = 2; + } else { + gc->dev[i].absmin[psx] = -1; + gc->dev[i].absmax[psx] = 1; + } } + + for (j = 0; j < 12; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); + break; - case -1: + case 0: gc->pads[GC_PSX] &= ~gc_status_bit[i]; - pbtn = 0; printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); break; default: gc->pads[GC_PSX] &= ~gc_status_bit[i]; - pbtn = 0; printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," " please report to <vojtech@suse.cz>.\n", psx); } - - for (j = 0; j < pbtn; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - break; } diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/iforce.c linux/drivers/char/joystick/iforce.c --- v2.4.3/linux/drivers/char/joystick/iforce.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/iforce.c Wed Apr 11 19:02:30 2001 @@ -33,6 +33,7 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <linux/usb.h> #include <linux/serio.h> #include <linux/config.h> diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/ns558.c linux/drivers/char/joystick/ns558.c --- v2.4.3/linux/drivers/char/joystick/ns558.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/ns558.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * $Id: ns558.c,v 1.16 2000/08/17 20:03:56 vojtech Exp $ + * $Id: ns558.c,v 1.27 2001/03/28 09:25:05 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst @@ -47,7 +47,7 @@ #define NS558_PNP 2 #define NS558_PCI 3 -static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209, +static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209, 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 }; struct ns558 { @@ -230,26 +230,30 @@ /* * PnP IDs: * + * @P@0001 - ALS 100 (no comp. ID) * CTL00c1 - SB AWE32 PnP * CTL00c3 - SB AWE64 PnP * CTL00f0 - SB16 PnP / Vibra 16x - * CTL7001 - SB Vibra16C PnP - * CSC0b35 - Crystal ** doesn't have compatibility ID ** + * CTL7001 - SB Vibra16C PnP (no comp. ID) + * CTL7002 - SB AWE32 (no comp. ID) + * CSC0b35 - Crystal (no comp. ID) * TER1141 - Terratec AD1818 * YMM0800 - Yamaha OPL3-SA3 * * PNPb02f - Generic gameport */ -static struct pnp_devid { - unsigned int vendor, device; -} pnp_devids[] = { - { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) }, - { ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) }, - { ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) }, +static struct isapnp_device_id pnp_devids[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 }, { 0, }, }; +MODULE_DEVICE_TABLE(isapnp, pnp_devids); + static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next) { int ioport, iolen; @@ -306,7 +310,7 @@ int i = 0; #ifdef NSS558_ISAPNP struct pci_dev *dev = NULL; - struct pnp_devid *devid; + struct isapnp_device_id *devid; #endif /* @@ -329,7 +333,7 @@ #ifdef NSS558_ISAPNP for (devid = pnp_devids; devid->vendor; devid++) { - while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) { + while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) { ns558 = ns558_pnp_probe(dev, ns558); } } diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/sidewinder.c linux/drivers/char/joystick/sidewinder.c --- v2.4.3/linux/drivers/char/joystick/sidewinder.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/sidewinder.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * $Id: sidewinder.c,v 1.16 2000/07/14 09:02:41 vojtech Exp $ + * $Id: sidewinder.c,v 1.18 2001/02/28 07:09:30 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -334,7 +334,7 @@ input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); for (j = 0; j < 10; j++) - input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); + input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); } return 0; diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/spaceball.c linux/drivers/char/joystick/spaceball.c --- v2.4.3/linux/drivers/char/joystick/spaceball.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/spaceball.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * $Id: spaceball.c,v 1.7 2000/06/24 11:55:40 vojtech Exp $ + * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -108,10 +108,8 @@ /* * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, - * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can - * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think) - * on whether the axis value is increasing, decreasing, or same as before. - * (I don't see why this is useful). + * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which + * can occur in the axis values. */ static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags) @@ -126,7 +124,7 @@ return; case '^': if (!spaceball->escape) { - spaceball->escape ^= 1; + spaceball->escape = 1; return; } spaceball->escape = 0; @@ -135,7 +133,7 @@ case 'S': if (spaceball->escape) { spaceball->escape = 0; - data = 0xd; + data &= 0x1f; } default: if (spaceball->escape) { diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/stinger.c linux/drivers/char/joystick/stinger.c --- v2.4.3/linux/drivers/char/joystick/stinger.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/stinger.c Wed Apr 11 19:02:30 2001 @@ -0,0 +1,200 @@ +/* + * $Id: stinger.c,v 1.1 2000/07/17 10:42:14 vojtech Exp $ + * + * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 2000 Mark Fletcher + * + * Sponsored by SuSE + */ + +/* + * Gravis Stinger gamepad driver for Linux + */ + +/* + * This program is free warftware; 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/serio.h> +#include <linux/init.h> + +/* + * Constants. + */ + +#define STINGER_MAX_LENGTH 8 + +static char *stinger_name = "Gravis Stinger"; + +/* + * Per-Stinger data. + */ + +struct stinger { + struct input_dev dev; + int idx; + unsigned char data[STINGER_MAX_LENGTH]; +}; + +/* + * stinger_process_packet() decodes packets the driver receives from the + * Stinger. It updates the data accordingly. + */ + +static void stinger_process_packet(struct stinger *stinger) +{ + struct input_dev *dev = &stinger->dev; + unsigned char *data = stinger->data; + + if (!stinger->idx) return; + + input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5)); + input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4)); + input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3)); + input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2)); + input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5)); + input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4)); + input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3)); + input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2)); + input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1)); + input_report_key(dev, BTN_START, (data[3] & 0x01)); + + input_report_abs(dev, ABS_X, ((data[1] & 0x3F) - ((data[0] & 0x01) << 6))); + input_report_abs(dev, ABS_Y, ((data[2] & 0x3F) - ((data[0] & 0x02) << 5))); + + return; +} + +/* + * stinger_interrupt() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct stinger* stinger = serio->private; + + /* All Stinger packets are 4 bytes */ + + if (stinger->idx < STINGER_MAX_LENGTH) + stinger->data[stinger->idx++] = data; + + if (stinger->idx == 4) { + stinger_process_packet(stinger); + stinger->idx = 0; + } + + return; +} + +/* + * stinger_disconnect() is the opposite of stinger_connect() + */ + +static void stinger_disconnect(struct serio *serio) +{ + struct stinger* stinger = serio->private; + input_unregister_device(&stinger->dev); + serio_close(serio); + kfree(stinger); +} + +/* + * stinger_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Stinger, and if found, registers + * it as an input device. + */ + +static void stinger_connect(struct serio *serio, struct serio_dev *dev) +{ + struct stinger *stinger; + int i; + + if (serio->type != (SERIO_RS232 | SERIO_STINGER)) + return; + + if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL))) + return; + + memset(stinger, 0, sizeof(struct stinger)); + + stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ + BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ + BIT(BTN_START) | BIT(BTN_SELECT); + stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + stinger->dev.name = stinger_name; + stinger->dev.idbus = BUS_RS232; + stinger->dev.idvendor = SERIO_STINGER; + stinger->dev.idproduct = 0x0001; + stinger->dev.idversion = 0x0100; + + for (i = 0; i < 2; i++) { + stinger->dev.absmax[ABS_X+i] = 64; + stinger->dev.absmin[ABS_X+i] = -64; + stinger->dev.absflat[ABS_X+i] = 4; + } + + stinger->dev.private = stinger; + + serio->private = stinger; + + if (serio_open(serio, dev)) { + kfree(stinger); + return; + } + + input_register_device(&stinger->dev); + + printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number); +} + +/* + * The serio device structure. + */ + +static struct serio_dev stinger_dev = { + interrupt: stinger_interrupt, + connect: stinger_connect, + disconnect: stinger_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init stinger_init(void) +{ + serio_register_device(&stinger_dev); + return 0; +} + +void __exit stinger_exit(void) +{ + serio_unregister_device(&stinger_dev); +} + +module_init(stinger_init); +module_exit(stinger_exit); diff -u --recursive --new-file v2.4.3/linux/drivers/char/joystick/tmdc.c linux/drivers/char/joystick/tmdc.c --- v2.4.3/linux/drivers/char/joystick/tmdc.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/joystick/tmdc.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $ + * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -49,6 +49,8 @@ #define TMDC_MODE_M3DI 1 #define TMDC_MODE_3DRP 3 +#define TMDC_MODE_AT 4 +#define TMDC_MODE_FM 8 #define TMDC_MODE_FGP 163 #define TMDC_BYTE_ID 10 @@ -57,21 +59,35 @@ #define TMDC_ABS 7 #define TMDC_ABS_HAT 4 -#define TMDC_BTN_PAD 10 -#define TMDC_BTN_JOY 16 +#define TMDC_BTN 16 static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; -static unsigned char tmdc_abs[TMDC_ABS] = +static signed char tmdc_abs[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; -static unsigned char tmdc_abs_hat[TMDC_ABS_HAT] = +static signed char tmdc_abs_hat[TMDC_ABS_HAT] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; -static unsigned short tmdc_btn_pad[TMDC_BTN_PAD] = +static signed char tmdc_abs_at[TMDC_ABS] = + { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; +static signed char tmdc_abs_fm[TMDC_ABS] = + { ABS_RX, ABS_RY, ABS_X, ABS_Y }; + +static short tmdc_btn_pad[TMDC_BTN] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; -static unsigned short tmdc_btn_joy[TMDC_BTN_JOY] = +static short tmdc_btn_joy[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; +static short tmdc_btn_fm[TMDC_BTN] = + { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; +static short tmdc_btn_at[TMDC_BTN] = + { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, + BTN_BASE3, BTN_BASE2, BTN_BASE }; + +static struct { + int x; + int y; +} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; struct tmdc { struct gameport *gameport; @@ -79,6 +95,11 @@ struct input_dev dev[2]; char name[2][64]; int mode[2]; + signed char *abs[2]; + short *btn[2]; + unsigned char absc[2]; + unsigned char btnc[2][4]; + unsigned char btno[2][4]; int used; int reads; int bads; @@ -145,7 +166,7 @@ struct tmdc *tmdc = (void *) private; struct input_dev *dev; unsigned char r, bad = 0; - int i, j; + int i, j, k, l; tmdc->reads++; @@ -162,44 +183,34 @@ dev = tmdc->dev + j; - for (i = 0; i < data[j][TMDC_BYTE_DEF] >> 4; i++) - input_report_abs(dev, tmdc_abs[i], data[j][tmdc_byte_a[i]]); + for (i = 0; i < tmdc->absc[j]; i++) { + if (tmdc->abs[j][i] < 0) continue; + input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]); + } switch (tmdc->mode[j]) { case TMDC_MODE_M3DI: i = tmdc_byte_d[0]; - input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); - - for (i = 0; i < 4; i++) - input_report_key(dev, tmdc_btn_joy[i], - (data[j][tmdc_byte_d[0]] >> (i + 4)) & 1); - for (i = 0; i < 2; i++) - input_report_key(dev, tmdc_btn_joy[i + 4], - (data[j][tmdc_byte_d[1]] >> (i + 6)) & 1); - break; - case TMDC_MODE_3DRP: - case TMDC_MODE_FGP: - - for (i = 0; i < 10; i++) - input_report_key(dev, tmdc_btn_pad[i], - (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1); + case TMDC_MODE_AT: + i = tmdc_byte_a[3]; + input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x); + input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y); break; - default: - - for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 0xf) << 3) && i < TMDC_BTN_JOY; i++) - input_report_key(dev, tmdc_btn_joy[i], - (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1); - - break; + } + for (k = l = 0; k < 4; k++) { + for (i = 0; i < tmdc->btnc[j][k]; i++) + input_report_key(dev, tmdc->btn[j][i + l], + ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); + l += tmdc->btnc[j][k]; } } @@ -229,20 +240,25 @@ static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev) { - struct tmdc *tmdc; - struct js_tm_models { + struct models { unsigned char id; char *name; char abs; char hats; - char joybtn; - char padbtn; - } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 0, 6, 0 }, - { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, 0, 10 }, - { 163, "Thrustmaster Fusion GamePad", 2, 0, 0, 10 }, - { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0, 0 }}; + char btnc[4]; + char btno[4]; + signed char *axes; + short *buttons; + } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, + { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, + { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, + { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }}; + unsigned char data[2][TMDC_MAX_LENGTH]; - int i, j, m; + struct tmdc *tmdc; + int i, j, k, l, m; if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL))) return; @@ -268,12 +284,23 @@ for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); + tmdc->abs[j] = models[m].axes; + tmdc->btn[j] = models[m].buttons; + if (!models[m].id) { models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; - models[m].joybtn = (data[j][TMDC_BYTE_DEF] & 0xf) << 3; + for (k = 0; k < 4; k++) + models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0; } - sprintf(tmdc->name[j], models[m].name, models[m].abs, models[m].joybtn, tmdc->mode[j]); + tmdc->absc[j] = models[m].abs; + for (k = 0; k < 4; k++) { + tmdc->btnc[j][k] = models[m].btnc[k]; + tmdc->btno[j][k] = models[m].btno[k]; + } + + sprintf(tmdc->name[j], models[m].name, models[m].abs, + (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); tmdc->dev[j].private = tmdc; tmdc->dev[j].open = tmdc_open; @@ -288,11 +315,12 @@ tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { - set_bit(tmdc_abs[i], tmdc->dev[j].absbit); - tmdc->dev[j].absmin[tmdc_abs[i]] = 8; - tmdc->dev[j].absmax[tmdc_abs[i]] = 248; - tmdc->dev[j].absfuzz[tmdc_abs[i]] = 2; - tmdc->dev[j].absflat[tmdc_abs[i]] = 4; + if (tmdc->abs[i] < 0) continue; + set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); + tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; + tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; + tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2; + tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4; } for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) { @@ -301,11 +329,11 @@ tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1; } - for (i = 0; i < models[m].joybtn && i < TMDC_BTN_JOY; i++) - set_bit(tmdc_btn_joy[i], tmdc->dev[j].keybit); - - for (i = 0; i < models[m].padbtn && i < TMDC_BTN_PAD; i++) - set_bit(tmdc_btn_pad[i], tmdc->dev[j].keybit); + for (k = l = 0; k < 4; k++) { + for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++) + set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit); + l += models[m].btnc[k]; + } input_register_device(tmdc->dev + j); printk(KERN_INFO "input%d: %s on gameport%d.%d\n", diff -u --recursive --new-file v2.4.3/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c --- v2.4.3/linux/drivers/char/machzwd.c Tue Mar 6 19:44:34 2001 +++ linux/drivers/char/machzwd.c Thu Apr 12 12:16:35 2001 @@ -26,6 +26,7 @@ * */ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <linux/types.h> diff -u --recursive --new-file v2.4.3/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.4.3/linux/drivers/char/mem.c Mon Mar 19 12:35:08 2001 +++ linux/drivers/char/mem.c Fri Apr 13 20:26:07 2001 @@ -41,6 +41,9 @@ #ifdef CONFIG_MDA_CONSOLE extern void mda_console_init(void); #endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) +extern void tapechar_init(void); +#endif #if defined(CONFIG_ADB) extern void adbdev_init(void); #endif @@ -639,6 +642,9 @@ #endif #ifdef CONFIG_FTAPE ftape_init(); +#endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) + tapechar_init(); #endif #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) tapechar_init(); diff -u --recursive --new-file v2.4.3/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.4.3/linux/drivers/char/misc.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/char/misc.c Fri Apr 13 20:26:07 2001 @@ -73,10 +73,8 @@ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int ds1286_init(void); -extern int dsp56k_init(void); extern int radio_init(void); extern int pmu_device_init(void); -extern int qpmouse_init(void); extern int tosh_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, @@ -173,10 +171,20 @@ int misc_register(struct miscdevice * misc) { static devfs_handle_t devfs_handle; - + struct miscdevice *c; + if (misc->next || misc->prev) return -EBUSY; down(&misc_sem); + c = misc_list.next; + + while ((c != &misc_list) && (c->minor != misc->minor)) + c = c->next; + if (c != &misc_list) { + up(&misc_sem); + return -EBUSY; + } + if (misc->minor == MISC_DYNAMIC_MINOR) { int i = DYNAMIC_MINORS; while (--i >= 0) @@ -245,9 +253,6 @@ int __init misc_init(void) { create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL); -#if defined CONFIG_82C710_MOUSE - qpmouse_init(); -#endif #ifdef CONFIG_MVME16x rtc_MK48T08_init(); #endif @@ -256,9 +261,6 @@ #endif #ifdef CONFIG_SGI_DS1286 ds1286_init(); -#endif -#ifdef CONFIG_ATARI_DSP56K - dsp56k_init(); #endif #ifdef CONFIG_MISC_RADIO radio_init(); diff -u --recursive --new-file v2.4.3/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c --- v2.4.3/linux/drivers/char/n_r3964.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/n_r3964.c Fri Apr 13 20:26:07 2001 @@ -7,7 +7,7 @@ * http://www.pap-philips.de * ----------------------------------------------------------- * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. * * Author: * L. Haag @@ -65,7 +65,7 @@ //#define DEBUG_QUEUE -/* Log successfull handshake and protocol operations */ +/* Log successful handshake and protocol operations */ //#define DEBUG_PROTO_S /* Log handshake and protocol errors: */ @@ -983,13 +983,14 @@ { queue_the_message: - save_flags(flags); - cli(); - pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL); TRACE_M("add_msg - kmalloc %x",(int)pMsg); - if(pMsg==NULL) + if(pMsg==NULL) { return; + } + + save_flags(flags); + cli(); pMsg->msg_id = msg_id; pMsg->arg = arg; diff -u --recursive --new-file v2.4.3/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.4.3/linux/drivers/char/n_tty.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/n_tty.c Fri Apr 6 10:42:55 2001 @@ -15,7 +15,7 @@ * This file also contains code originally written by Linus Torvalds, * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. * - * This file may be redistributed under the terms of the GNU Public + * This file may be redistributed under the terms of the GNU General Public * License. * * Reduced memory usage for older ARM systems - Russell King. @@ -100,7 +100,7 @@ unsigned long flags; /* * The problem of stomping on the buffers ends here. - * Why didn't anyone see this one comming? --AJK + * Why didn't anyone see this one coming? --AJK */ spin_lock_irqsave(&tty->read_lock, flags); put_tty_queue_nolock(c, tty); diff -u --recursive --new-file v2.4.3/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.4.3/linux/drivers/char/pc_keyb.c Fri Mar 2 18:38:37 2001 +++ linux/drivers/char/pc_keyb.c Fri Apr 6 10:42:55 2001 @@ -1016,6 +1016,8 @@ misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (queue == NULL) + panic("psaux_init(): out of memory"); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); diff -u --recursive --new-file v2.4.3/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.4.3/linux/drivers/char/pcwd.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/pcwd.c Fri Apr 6 10:42:55 2001 @@ -462,8 +462,8 @@ outb_p(0xA5, current_readport + 3); spin_unlock(&io_lock); } - unlock_kernel(); #endif + unlock_kernel(); } return 0; } diff -u --recursive --new-file v2.4.3/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.4.3/linux/drivers/char/qpmouse.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/qpmouse.c Fri Apr 13 20:26:07 2001 @@ -24,9 +24,8 @@ */ #include <linux/module.h> - -#include <linux/sched.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/fcntl.h> #include <linux/errno.h> @@ -146,11 +145,11 @@ fasync_qp(-1, file, 0); if (!--qp_count) { if (!poll_qp_status()) - printk("Warning: Mouse device busy in release_qp()\n"); + printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); status = inb_p(qp_status); outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); if (!poll_qp_status()) - printk("Warning: Mouse device busy in release_qp()\n"); + printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); free_irq(QP_IRQ, NULL); } unlock_kernel(); @@ -188,7 +187,7 @@ outb_p(status, qp_status); /* Enable interrupts */ while (!poll_qp_status()) { - printk("Error: Mouse device busy in open_qp()\n"); + printk(KERN_ERR "Error: Mouse device busy in open_qp()\n"); qp_count--; status &= ~(QP_ENABLE|QP_INTS_ON); outb_p(status, qp_status); @@ -303,7 +302,9 @@ * Initialize driver. */ static struct miscdevice qp_mouse = { - PSMOUSE_MINOR, "QPmouse", &qp_fops + minor: PSMOUSE_MINOR, + name: "QPmouse", + fops: &qp_fops, }; /* @@ -337,37 +338,36 @@ return 1; } -int __init qpmouse_init(void) +static const char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n"; +static const char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n"; + +static int __init qpmouse_init_driver(void) { if (!probe_qp()) return -EIO; - printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n"); + printk(msg_banner); + /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if(queue==NULL) - { - printk(KERN_ERR "qpmouse: no queue memory.\n"); + if (queue == NULL) { + printk(msg_nomem); return -ENOMEM; - } + } qp_present = 1; misc_register(&qp_mouse); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); - return 0; } -#ifdef MODULE -int init_module(void) -{ - return qpmouse_init(); -} - -void cleanup_module(void) +static void __exit qpmouse_exit_driver(void) { misc_deregister(&qp_mouse); kfree(queue); } -#endif + +module_init(qpmouse_init_driver); +module_exit(qpmouse_exit_driver); + diff -u --recursive --new-file v2.4.3/linux/drivers/char/qtronix.c linux/drivers/char/qtronix.c --- v2.4.3/linux/drivers/char/qtronix.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/qtronix.c Fri Apr 13 20:26:07 2001 @@ -0,0 +1,597 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Qtronix 990P infrared keyboard driver. + * + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or support@mvista.com + * + * + * The bottom portion of this driver was take from + * pc_keyb.c Please see that file for copyrights. + * + * 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 <linux/config.h> + +/* + * NOTE: + * + * This driver has only been tested with the Consumer IR + * port of the ITE 8172 system controller. + * + * You do not need this driver if you are using the ps/2 or + * USB adapter that the keyboard ships with. You only need + * this driver if your board has a IR port and the keyboard + * data is being sent directly to the IR. In that case, + * you also need some low-level IR support. See it8172_cir.c. + * + */ + +#ifdef CONFIG_QTRONIX_KEYBOARD + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_int.h> +#include <asm/it8172/it8172_cir.h> + +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/signal.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/delay.h> +#include <linux/random.h> +#include <linux/poll.h> +#include <linux/miscdevice.h> +#include <linux/malloc.h> +#include <linux/kbd_kern.h> +#include <linux/smp_lock.h> +#include <asm/io.h> +#include <linux/pc_keyb.h> + +#include <asm/keyboard.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <asm/system.h> + +#define leading1 0 +#define leading2 0xF + +#define KBD_CIR_PORT 0 +#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */ + +static int data_index; +struct cir_port *cir; +static unsigned char kbdbytes[5]; +static unsigned char cir_data[32]; /* we only need 16 chars */ + +static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs); +static int handle_data(unsigned char *p_data); +static inline void handle_mouse_event(unsigned char scancode); +static inline void handle_keyboard_event(unsigned char scancode, int down); +static int __init psaux_init(void); + +static struct aux_queue *queue; /* Mouse data buffer. */ +static int aux_count = 0; + +/* + * Keys accessed through the 'Fn' key + * The Fn key does not produce a key-up sequence. So, the first + * time the user presses it, it will be key-down event. The key + * stays down until the user presses it again. + */ +#define NUM_FN_KEYS 56 +static unsigned char fn_keys[NUM_FN_KEYS] = { + 0,0,0,0,0,0,0,0, /* 0 7 */ + 8,9,10,93,0,0,0,0, /* 8 15 */ + 0,0,0,0,0,0,0,5, /* 16 23 */ + 6,7,91,0,0,0,0,0, /* 24 31 */ + 0,0,0,0,0,2,3,4, /* 32 39 */ + 92,0,0,0,0,0,0,0, /* 40 47 */ + 0,0,0,0,11,0,94,95 /* 48 55 */ + +}; + +void init_qtronix_990P_kbd(void) +{ + int retval; + + cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL); + if (!cir) { + printk("Unable to initialize Qtronix keyboard\n"); + return; + } + + /* + * revisit + * this should be programmable, somehow by the, by the user. + */ + cir->port = KBD_CIR_PORT; + cir->baud_rate = 0x1d; + cir->rdwos = 0; + cir->rxdcr = 0x3; + cir->hcfs = 0; + cir->fifo_tl = 0; + cir->cfq = 0x1d; + cir_port_init(cir); + + retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler, + (unsigned long )(SA_INTERRUPT|SA_SHIRQ), + (const char *)"Qtronix IR Keyboard", (void *)cir); + + if (retval) { + printk("unable to allocate cir %d irq %d\n", + cir->port, IT8172_CIR0_IRQ); + } +#ifdef CONFIG_PSMOUSE + psaux_init(); +#endif +} + +static inline unsigned char BitReverse(unsigned short key) +{ + unsigned char rkey = 0; + rkey |= (key & 0x1) << 7; + rkey |= (key & 0x2) << 5; + rkey |= (key & 0x4) << 3; + rkey |= (key & 0x8) << 1; + rkey |= (key & 0x10) >> 1; + rkey |= (key & 0x20) >> 3; + rkey |= (key & 0x40) >> 5; + rkey |= (key & 0x80) >> 7; + return rkey; + +} + + +static inline u_int8_t UpperByte(u_int8_t data) +{ + return (data >> 4); +} + + +static inline u_int8_t LowerByte(u_int8_t data) +{ + return (data & 0xF); +} + + +int CheckSumOk(u_int8_t byte1, u_int8_t byte2, + u_int8_t byte3, u_int8_t byte4, u_int8_t byte5) +{ + u_int8_t CheckSum; + + CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5; + if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) ) + return 0; + else + return 1; +} + + +static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cir_port *cir; + int j; + unsigned char int_status; + + cir = (struct cir_port *)dev_id; + int_status = get_int_status(cir);; + if (int_status & 0x4) { + clear_fifo(cir); + return; + } + + while (cir_get_rx_count(cir)) { + + cir_data[data_index] = cir_read_data(cir); + + if (data_index == 0) {/* expecting first byte */ + if (cir_data[data_index] != leading1) { + //printk("!leading byte %x\n", cir_data[data_index]); + set_rx_active(cir); + clear_fifo(cir); + continue; + } + } + if (data_index == 1) { + if ((cir_data[data_index] & 0xf) != leading2) { + set_rx_active(cir); + data_index = 0; /* start over */ + clear_fifo(cir); + continue; + } + } + + if ( (cir_data[data_index] == 0xff)) { /* last byte */ + //printk("data_index %d\n", data_index); + set_rx_active(cir); +#if 0 + for (j=0; j<=data_index; j++) { + printk("rx_data %d: %x\n", j, cir_data[j]); + } +#endif + data_index = 0; + handle_data(cir_data); + return; + } + else if (data_index>16) { + set_rx_active(cir); +#if 0 + printk("warning: data_index %d\n", data_index); + for (j=0; j<=data_index; j++) { + printk("rx_data %d: %x\n", j, cir_data[j]); + } +#endif + data_index = 0; + clear_fifo(cir); + return; + } + data_index++; + } +} + + +#define NUM_KBD_BYTES 5 +static int handle_data(unsigned char *p_data) +{ + u_int32_t bit_bucket; + u_int32_t i, j; + u_int32_t got_bits, next_byte; + int down = 0; + + /* Reorganize the bit stream */ + for (i=0; i<16; i++) + p_data[i] = BitReverse(~p_data[i]); + + /* + * We've already previously checked that p_data[0] + * is equal to leading1 and that (p_data[1] & 0xf) + * is equal to leading2. These twelve bits are the + * leader code. We can now throw them away (the 12 + * bits) and continue parsing the stream. + */ + bit_bucket = p_data[1] << 12; + got_bits = 4; + next_byte = 2; + + /* + * Process four bits at a time + */ + for (i=0; i<NUM_KBD_BYTES; i++) { + + kbdbytes[i]=0; + + for (j=0; j<8; j++) /* 8 bits per byte */ + { + if (got_bits < 4) { + bit_bucket |= (p_data[next_byte++] << (8 - got_bits)); + got_bits += 8; + } + + if ((bit_bucket & 0xF000) == 0x8000) { + /* Convert 1000b to 1 */ + kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1); + got_bits -= 4; + bit_bucket = bit_bucket << 4; + } + else if ((bit_bucket & 0xC000) == 0x8000) { + /* Convert 10b to 0 */ + kbdbytes[i] = kbdbytes[i] >> 1; + got_bits -= 2; + bit_bucket = bit_bucket << 2; + } + else { + /* bad serial stream */ + return 1; + } + + if (next_byte > 16) { + //printk("error: too many bytes\n"); + return 1; + } + } + } + + + if (!CheckSumOk(kbdbytes[0], kbdbytes[1], + kbdbytes[2], kbdbytes[3], kbdbytes[4])) { + //printk("checksum failed\n"); + return 1; + } + + if (kbdbytes[1] & 0x08) { + //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]); + handle_mouse_event(kbdbytes[1]); + handle_mouse_event(kbdbytes[2]); + handle_mouse_event(kbdbytes[3]); + } + else { + if (kbdbytes[2] == 0) down = 1; +#if 0 + if (down) + printk("down %d\n", kbdbytes[3]); + else + printk("up %d\n", kbdbytes[3]); +#endif + handle_keyboard_event(kbdbytes[3], down); + } + return 0; +} + + +spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); + + +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + printk("pckbd_setkeycode scancode %x keycode %x\n", scancode, keycode); + return 0; +} + +int pckbd_getkeycode(unsigned int scancode) +{ + return scancode; +} + + +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode = 0; + + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + /* todo */ + if (!prev_scancode && scancode == 160) { /* Fn key down */ + //printk("Fn key down\n"); + prev_scancode = 160; + return 0; + } + else if (prev_scancode && scancode == 160) { /* Fn key up */ + //printk("Fn key up\n"); + prev_scancode = 0; + return 0; + } + + /* todo */ + if (prev_scancode == 160) { + if (scancode <= NUM_FN_KEYS) { + *keycode = fn_keys[scancode]; + //printk("fn keycode %d\n", *keycode); + } + else + return 0; + } + else if (scancode <= 127) { + *keycode = scancode; + } + else + return 0; + + + return 1; +} + +char pckbd_unexpected_up(unsigned char keycode) +{ + //printk("pckbd_unexpected_up\n"); + return 0; +} + +static unsigned char kbd_exists = 1; + +static inline void handle_keyboard_event(unsigned char scancode, int down) +{ + kbd_exists = 1; + handle_scancode(scancode, down); + tasklet_schedule(&keyboard_tasklet); +} + + +void pckbd_leds(unsigned char leds) +{ +} + +/* dummy */ +void pckbd_init_hw(void) +{ +} + + + +static inline void handle_mouse_event(unsigned char scancode) +{ + if(scancode == AUX_RECONNECT){ + queue->head = queue->tail = 0; /* Flush input queue */ + // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ + return; + } + + add_mouse_randomness(scancode); + if (aux_count) { + int head = queue->head; + + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } + } +} + +static unsigned char get_from_queue(void) +{ + unsigned char result; + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + return result; +} + + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int fasync_aux(int fd, struct file *filp, int on) +{ + int retval; + + //printk("fasync_aux\n"); + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + + +/* + * Random magic cookie for the aux device + */ +#define AUX_DEV ((void *)queue) + +static int release_aux(struct inode * inode, struct file * file) +{ + lock_kernel(); + fasync_aux(-1, file, 0); + aux_count--; + unlock_kernel(); + return 0; +} + +static int open_aux(struct inode * inode, struct file * file) +{ + if (aux_count++) { + return 0; + } + queue->head = queue->tail = 0; /* Flush input queue */ + return 0; +} + +/* + * Put bytes from input queue to buffer. + */ + +static ssize_t read_aux(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_user(c, buffer++); + i--; + } + if (count-i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* + * Write to the aux device. + */ + +static ssize_t write_aux(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + /* + * The ITE boards this was tested on did not have the + * transmit wires connected. + */ + return count; +} + +static unsigned int aux_poll(struct file *file, poll_table * wait) +{ + poll_wait(file, &queue->proc_list, wait); + if (!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations psaux_fops = { + read: read_aux, + write: write_aux, + poll: aux_poll, + open: open_aux, + release: release_aux, + fasync: fasync_aux, +}; + +/* + * Initialize driver. + */ +static struct miscdevice psaux_mouse = { + PSMOUSE_MINOR, "psaux", &psaux_fops +}; + +static int __init psaux_init(void) +{ + misc_register(&psaux_mouse); + queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + + return 0; +} +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/char/qtronixmap.map linux/drivers/char/qtronixmap.map --- v2.4.3/linux/drivers/char/qtronixmap.map Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/qtronixmap.map Fri Apr 13 20:26:07 2001 @@ -0,0 +1,287 @@ +# Default kernel keymap. This uses 7 modifier combinations. +keymaps 0-2,4-5,8,12 +# Change the above line into +# keymaps 0-2,4-6,8,12 +# in case you want the entries +# altgr control keycode 83 = Boot +# altgr control keycode 111 = Boot +# below. +# +# In fact AltGr is used very little, and one more keymap can +# be saved by mapping AltGr to Alt (and adapting a few entries): +# keycode 100 = Alt +# +keycode 1 = grave asciitilde + alt keycode 1 = Meta_Escape +keycode 2 = one exclam + alt keycode 2 = Meta_one +keycode 3 = two at at + control keycode 3 = nul + shift control keycode 3 = nul + alt keycode 3 = Meta_two +keycode 4 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three +keycode 5 = four dollar dollar + control keycode 5 = Control_backslash + alt keycode 5 = Meta_four +keycode 6 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five +keycode 7 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six +keycode 8 = seven ampersand braceleft + control keycode 8 = Control_underscore + alt keycode 8 = Meta_seven +keycode 9 = eight asterisk bracketleft + control keycode 9 = Delete + alt keycode 9 = Meta_eight +keycode 10 = nine parenleft bracketright + alt keycode 10 = Meta_nine +keycode 11 = zero parenright braceright + alt keycode 11 = Meta_zero +keycode 12 = minus underscore backslash + control keycode 12 = Control_underscore + shift control keycode 12 = Control_underscore + alt keycode 12 = Meta_minus +keycode 13 = equal plus + alt keycode 13 = Meta_equal +keycode 15 = Delete Delete + control keycode 15 = BackSpace + alt keycode 15 = Meta_Delete +keycode 16 = Tab Tab + alt keycode 16 = Meta_Tab +keycode 17 = q +keycode 18 = w +keycode 19 = e +keycode 20 = r +keycode 21 = t +keycode 22 = y +keycode 23 = u +keycode 24 = i +keycode 25 = o +keycode 26 = p +keycode 27 = bracketleft braceleft + control keycode 27 = Escape + alt keycode 27 = Meta_bracketleft +keycode 28 = bracketright braceright + control keycode 28 = Control_bracketright + alt keycode 28 = Meta_bracketright +keycode 29 = backslash bar + control keycode 29 = Control_backslash + alt keycode 29 = Meta_backslash +keycode 30 = Caps_Lock +keycode 31 = a +keycode 32 = s +keycode 33 = d +keycode 34 = f +keycode 35 = g +keycode 36 = h +keycode 37 = j +keycode 38 = k +keycode 39 = l +keycode 40 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 41 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 42 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave +keycode 43 = Return + alt keycode 43 = Meta_Control_m +keycode 44 = Shift +keycode 46 = z +keycode 47 = x +keycode 48 = c +keycode 49 = v +keycode 50 = b +keycode 51 = n +keycode 52 = m +keycode 53 = comma less + alt keycode 51 = Meta_comma +keycode 54 = period greater + control keycode 52 = Compose + alt keycode 52 = Meta_period +keycode 55 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash +keycode 57 = Shift +keycode 58 = Control +keycode 60 = Alt +keycode 61 = space space + control keycode 61 = nul + alt keycode 61 = Meta_space +keycode 62 = Alt + +keycode 75 = Insert +keycode 76 = Delete + +keycode 83 = Up +keycode 84 = Down + +keycode 85 = Prior + shift keycode 85 = Scroll_Backward +keycode 86 = Next + shift keycode 86 = Scroll_Forward +keycode 89 = Right + alt keycode 89 = Incr_Console +keycode 79 = Left + alt keycode 79 = Decr_Console + +keycode 90 = Num_Lock + shift keycode 90 = Bare_Num_Lock + +keycode 91 = minus +keycode 92 = plus +keycode 93 = KP_Multiply +keycode 94 = period +keycode 95 = KP_Divide + +keycode 107 = Select +keycode 108 = Down + +keycode 110 = Escape Escape + alt keycode 1 = Meta_Escape + +keycode 112 = F1 F11 Console_13 + control keycode 112 = F1 + alt keycode 112 = Console_1 + control alt keycode 112 = Console_1 +keycode 113 = F2 F12 Console_14 + control keycode 113 = F2 + alt keycode 113 = Console_2 + control alt keycode 113 = Console_2 +keycode 114 = F3 F13 Console_15 + control keycode 114 = F3 + alt keycode 114 = Console_3 + control alt keycode 114 = Console_3 +keycode 115 = F4 F14 Console_16 + control keycode 115 = F4 + alt keycode 115 = Console_4 + control alt keycode 115 = Console_4 +keycode 116 = F5 F15 Console_17 + control keycode 116 = F5 + alt keycode 116 = Console_5 + control alt keycode 116 = Console_5 +keycode 117 = F6 F16 Console_18 + control keycode 117 = F6 + alt keycode 117 = Console_6 + control alt keycode 117 = Console_6 +keycode 118 = F7 F17 Console_19 + control keycode 118 = F7 + alt keycode 118 = Console_7 + control alt keycode 118 = Console_7 +keycode 119 = F8 F18 Console_20 + control keycode 119 = F8 + alt keycode 119 = Console_8 + control alt keycode 119 = Console_8 +keycode 120 = F9 F19 Console_21 + control keycode 120 = F9 + alt keycode 120 = Console_9 + control alt keycode 120 = Console_9 +keycode 121 = F10 F20 Console_22 + control keycode 121 = F10 + alt keycode 121 = Console_10 + control alt keycode 121 = Console_10 + +keycode 126 = Pause + + +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Macro = "\033[M" +string Pause = "\033[P" +compose '`' 'A' to 'Ŕ' +compose '`' 'a' to 'ŕ' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ă' +compose '~' 'a' to 'ă' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Ĺ' +compose 'o' 'a' to 'ĺ' +compose '0' 'A' to 'Ĺ' +compose '0' 'a' to 'ĺ' +compose 'A' 'A' to 'Ĺ' +compose 'a' 'a' to 'ĺ' +compose 'A' 'E' to 'Ć' +compose 'a' 'e' to 'ć' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'Č' +compose '`' 'e' to 'č' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ę' +compose '^' 'e' to 'ę' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ě' +compose '`' 'i' to 'ě' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ď' +compose '"' 'i' to 'ď' +compose '-' 'D' to 'Đ' +compose '-' 'd' to 'đ' +compose '~' 'N' to 'Ń' +compose '~' 'n' to 'ń' +compose '`' 'O' to 'Ň' +compose '`' 'o' to 'ň' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Ő' +compose '~' 'o' to 'ő' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ř' +compose '/' 'o' to 'ř' +compose '`' 'U' to 'Ů' +compose '`' 'u' to 'ů' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Ű' +compose '^' 'u' to 'ű' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Ţ' +compose 't' 'h' to 'ţ' +compose 's' 's' to 'ß' +compose '"' 'y' to '˙' +compose 's' 'z' to 'ß' +compose 'i' 'j' to '˙' diff -u --recursive --new-file v2.4.3/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c --- v2.4.3/linux/drivers/char/rio/rio_linux.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/rio/rio_linux.c Fri Apr 13 20:26:07 2001 @@ -1031,8 +1031,10 @@ free2:kfree (p->RIOHosts); free1:kfree (p); free0: - rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", - p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios); + if (p) { + rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", + p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios); + } return -ENOMEM; } diff -u --recursive --new-file v2.4.3/linux/drivers/char/rio/rioctrl.c linux/drivers/char/rio/rioctrl.c --- v2.4.3/linux/drivers/char/rio/rioctrl.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/rio/rioctrl.c Fri Apr 13 20:26:07 2001 @@ -764,7 +764,7 @@ PortP->Config &= ~RIO_WAITDRAIN; } /* - ** Store setings if locking or unlocking port or if the + ** Store settings if locking or unlocking port or if the ** port is not locked, when setting the store option. */ if (PortP->Mapped && diff -u --recursive --new-file v2.4.3/linux/drivers/char/scan_keyb.c linux/drivers/char/scan_keyb.c --- v2.4.3/linux/drivers/char/scan_keyb.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/scan_keyb.c Wed Apr 11 21:24:52 2001 @@ -18,33 +18,40 @@ #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/kbd_kern.h> +#include <linux/timer.h> + +#define SCANHZ (HZ/20) struct scan_keyboard { struct scan_keyboard *next; - void (*scan)(unsigned char *buffer); + int (*scan)(unsigned char *buffer); const unsigned char *table; unsigned char *s0, *s1; int length; }; - + +static int scan_jiffies=0; static struct scan_keyboard *keyboards=NULL; -static struct tq_struct task_scan_kbd; +struct timer_list scan_timer; static void check_kbd(const unsigned char *table, unsigned char *new, unsigned char *old, int length) { int need_tasklet_schedule=0; - unsigned char xor, bit; + unsigned int xor, bit; while(length-->0) { if((xor=*new^*old)==0) { table+=8; } else { - for(bit=0x80; bit!=0; bit>>=1) { + for(bit=0x01; bit<0x100; bit<<=1) { if(xor&bit) { handle_scancode(*table, !(*new&bit)); need_tasklet_schedule=1; +#if 0 + printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed"); +#endif } table++; } @@ -57,26 +64,39 @@ } -static void scan_kbd(void *dummy) +static void scan_kbd(unsigned long dummy) { struct scan_keyboard *kbd; + scan_jiffies++; + for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) { - if(jiffies&1) { - kbd->scan(kbd->s0); - check_kbd(kbd->table, kbd->s0, kbd->s1, kbd->length); + if(scan_jiffies&1) { + if(!kbd->scan(kbd->s0)) + check_kbd(kbd->table, + kbd->s0, kbd->s1, kbd->length); + else + memcpy(kbd->s0, kbd->s1, kbd->length); } else { - kbd->scan(kbd->s1); - check_kbd(kbd->table, kbd->s1, kbd->s0, kbd->length); + if(!kbd->scan(kbd->s1)) + check_kbd(kbd->table, + kbd->s1, kbd->s0, kbd->length); + else + memcpy(kbd->s1, kbd->s0, kbd->length); } } - queue_task(&task_scan_kbd, &tq_timer); + + init_timer(&scan_timer); + scan_timer.expires = jiffies + SCANHZ; + scan_timer.data = 0; + scan_timer.function = scan_kbd; + add_timer(&scan_timer); } -int register_scan_keyboard(void (*scan)(unsigned char *buffer), +int register_scan_keyboard(int (*scan)(unsigned char *buffer), const unsigned char *table, int length) { @@ -98,8 +118,8 @@ if (kbd->s1 == NULL) goto error_free_s0; - kbd->scan(kbd->s0); - kbd->scan(kbd->s1); + memset(kbd->s0, -1, kbd->length); + memset(kbd->s1, -1, kbd->length); kbd->next=keyboards; keyboards=kbd; @@ -119,11 +139,11 @@ void __init scan_kbd_init(void) { + init_timer(&scan_timer); + scan_timer.expires = jiffies + SCANHZ; + scan_timer.data = 0; + scan_timer.function = scan_kbd; + add_timer(&scan_timer); - INIT_LIST_HEAD(task_scan_kbd.list); - task_scan_kbd.sync=0; - task_scan_kbd.routine=scan_kbd; - task_scan_kbd.data=NULL; - queue_task(&task_scan_kbd, &tq_timer); printk(KERN_INFO "Generic scan keyboard driver initialized\n"); } diff -u --recursive --new-file v2.4.3/linux/drivers/char/scan_keyb.h linux/drivers/char/scan_keyb.h --- v2.4.3/linux/drivers/char/scan_keyb.h Fri Jul 21 14:21:06 2000 +++ linux/drivers/char/scan_keyb.h Wed Apr 11 21:24:52 2001 @@ -6,7 +6,7 @@ * Generic scan keyboard driver */ -int register_scan_keyboard(void (*scan)(unsigned char *buffer), +int register_scan_keyboard(int (*scan)(unsigned char *buffer), const unsigned char *table, int length); diff -u --recursive --new-file v2.4.3/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.3/linux/drivers/char/serial.c Tue Mar 6 20:13:51 2001 +++ linux/drivers/char/serial.c Fri Apr 13 20:26:07 2001 @@ -59,8 +59,8 @@ * */ -static char *serial_version = "5.05"; -static char *serial_revdate = "2000-12-13"; +static char *serial_version = "5.05a"; +static char *serial_revdate = "2001-03-20"; /* * Serial driver configuration section. Here are the various options: @@ -3924,11 +3924,6 @@ return; } - if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) { - printk("serial: PCI device enable failed\n"); - return; - } - /* * Run the initialization function, if any */ @@ -4610,7 +4605,8 @@ * (Should we try to make guesses for multiport serial devices * later?) */ - if ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL || + if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || (dev->class & 0xff) > 6) return 1; @@ -4639,6 +4635,7 @@ const struct pci_device_id *ent) { struct pci_board *board, tmp; + int rc; for (board = pci_boards; board->vendor; board++) { if (board->vendor != (unsigned short) PCI_ANY_ID && @@ -4656,6 +4653,9 @@ break; } + rc = pci_enable_device(dev); + if (rc) return rc; + if (board->vendor == 0 && serial_pci_guess_board(dev, board)) return -ENODEV; else if (serial_pci_guess_board(dev, &tmp) == 0) { @@ -4708,6 +4708,8 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = { { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, }, { 0, } }; @@ -5724,6 +5726,10 @@ case 9600: default: cflag |= B9600; + /* + * Set this to a sane value to prevent a divide error + */ + baud = 9600; break; } switch(bits) { diff -u --recursive --new-file v2.4.3/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c --- v2.4.3/linux/drivers/char/sh-sci.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/char/sh-sci.c Wed Apr 11 21:24:52 2001 @@ -74,6 +74,8 @@ static void sci_hungup(void *ptr); static void sci_close(void *ptr); static int sci_chars_in_buffer(void *ptr); +static int sci_request_irq(struct sci_port *port); +static void sci_free_irq(struct sci_port *port); static int sci_init_drivers(void); static struct tty_driver sci_driver, sci_callout_driver; @@ -83,8 +85,8 @@ static struct termios *sci_termios[SCI_NPORTS]; static struct termios *sci_termios_locked[SCI_NPORTS]; -int sci_refcount; -int sci_debug = 0; +static int sci_refcount; +static int sci_debug = 0; #ifdef MODULE MODULE_PARM(sci_debug, "i"); @@ -102,7 +104,7 @@ do status = sci_in(port, SCxSR); while (!(status & SCxSR_TDxE(port))); - + sci_out(port, SCxTDR, c); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); @@ -626,10 +628,10 @@ dprintk("sci: BREAK detected\n"); } -#if defined(CONFIG_CPU_SUBTYPE_SH7750) +#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) /* XXX: Handle SCIF overrun error */ - if (port->type == PORT_SCIF && (ctrl_inw(SCLSR2) & SCIF_ORER) != 0) { - ctrl_outw(0, SCLSR2); + if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { + sci_out(port, SCLSR, 0); if(tty->flip.count<TTY_FLIPBUF_SIZE) { copied++; *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; @@ -796,6 +798,7 @@ port->gs.flags &= ~ GS_ACTIVE; if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) sci_setsignals(port, 0, 0); + sci_free_irq(port); } /* ********************************************************************** * @@ -828,8 +831,7 @@ */ retval = gs_init_port(&port->gs); if (retval) { - port->gs.count--; - return retval; + goto failed_1; } port->gs.flags |= GS_ACTIVE; @@ -837,14 +839,17 @@ if (port->gs.count == 1) { MOD_INC_USE_COUNT; + + retval = sci_request_irq(port); + if (retval) { + goto failed_2; + } } retval = gs_block_til_ready(port, filp); if (retval) { - MOD_DEC_USE_COUNT; - port->gs.count--; - return retval; + goto failed_3; } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { @@ -870,6 +875,14 @@ port->gs.pgrp = current->pgrp; return 0; + +failed_3: + sci_free_irq(port); +failed_2: + MOD_DEC_USE_COUNT; +failed_1: + port->gs.count--; + return retval; } static void sci_hungup(void *ptr) @@ -1094,29 +1107,46 @@ return 0; } -int __init sci_init(void) +static int sci_request_irq(struct sci_port *port) { - struct sci_port *port; - int i, j; + int i; void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, sci_br_interrupt, }; + for (i=0; i<4; i++) { + if (!port->irqs[i]) continue; + if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, + "sci", port)) { + printk(KERN_ERR "sci: Cannot allocate irq.\n"); + return -ENODEV; + } + } + return 0; +} + +static void sci_free_irq(struct sci_port *port) +{ + int i; + + for (i=0; i<4; i++) { + if (!port->irqs[i]) continue; + free_irq(port->irqs[i], port); + } +} + +int __init sci_init(void) +{ + struct sci_port *port; + int j; + printk("SuperH SCI(F) driver initialized\n"); for (j=0; j<SCI_NPORTS; j++) { port = &sci_ports[j]; printk("ttySC%d at 0x%08x is a %s\n", j, port->base, (port->type == PORT_SCI) ? "SCI" : "SCIF"); - for (i=0; i<4; i++) { - if (!port->irqs[i]) continue; - if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, - "sci", port)) { - printk(KERN_ERR "sci: Cannot allocate irq.\n"); - return -ENODEV; - } - } } sci_init_drivers(); @@ -1135,11 +1165,6 @@ void cleanup_module(void) { - int i; - - for (i=SCI_ERI_IRQ; i<SCI_TEI_IRQ; i++) /* XXX: irq_end?? */ - free_irq(i, port); - tty_unregister_driver(&sci_driver); tty_unregister_driver(&sci_callout_driver); } diff -u --recursive --new-file v2.4.3/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h --- v2.4.3/linux/drivers/char/sh-sci.h Mon Oct 2 11:57:34 2000 +++ linux/drivers/char/sh-sci.h Wed Apr 11 21:24:52 2001 @@ -25,6 +25,7 @@ #define SH3_SCIF_IRQS { 56, 57, 59, 58 } #define SH3_IRDA_IRQS { 52, 53, 55, 54 } #define SH4_SCIF_IRQS { 40, 41, 43, 42 } +#define STB1_SCIF1_IRQS {23, 24, 26, 25 } #if defined(CONFIG_CPU_SUBTYPE_SH7708) # define SCI_NPORTS 1 @@ -53,12 +54,22 @@ } # define SCSPTR1 0xffe0001c /* 8 bit SCI */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ -# define SCLSR2 0xFFE80024 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) # define SCI_AND_SCIF +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +# define SCI_NPORTS 2 +# define SCI_INIT { \ + { {}, PORT_SCIF, 0xffe00000, STB1_SCIF1_IRQS, sci_init_pins_scif }, \ + { {}, PORT_SCIF, 0xffe80000, SH4_SCIF_IRQS, sci_init_pins_scif } \ +} +# define SCSPTR1 0xffe00020 /* 16 bit SCIF */ +# define SCSPTR2 0xffe80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #else # error CPU subtype not defined #endif @@ -260,6 +271,7 @@ SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCLSR, 0, 0, 0x24, 16) #define sci_in(port, reg) sci_##reg##_in(port) #define sci_out(port, reg, value) sci_##reg##_out(port, value) @@ -285,11 +297,24 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7750) static inline int sci_rxd_in(struct sci_port *port) { +#ifndef SCIF_ONLY if (port->base == 0xffe00000) return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ +#endif +#ifndef SCI_ONLY if (port->base == 0xffe80000) return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ +#endif return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xffe00000) + return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */ + else + return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + } #endif diff -u --recursive --new-file v2.4.3/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.4.3/linux/drivers/char/sx.c Tue Mar 6 19:44:34 2001 +++ linux/drivers/char/sx.c Fri Apr 6 10:42:55 2001 @@ -1767,6 +1767,20 @@ } +static void sx_break (struct tty_struct * tty, int flag) +{ + struct sx_port *port = tty->driver_data; + int rv; + + if (flag) + rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK); + else + rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN); + if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n", + read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat))); +} + + static int sx_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -1835,7 +1849,6 @@ sx_reconfigure_port(port); } break; - default: rc = -ENOIOCTLCMD; break; @@ -2215,6 +2228,7 @@ sx_driver.table = sx_table; sx_driver.termios = sx_termios; sx_driver.termios_locked = sx_termios_locked; + sx_driver.break_ctl = sx_break; sx_driver.open = sx_open; sx_driver.close = gs_close; diff -u --recursive --new-file v2.4.3/linux/drivers/char/toshiba.c linux/drivers/char/toshiba.c --- v2.4.3/linux/drivers/char/toshiba.c Wed Sep 27 13:53:56 2000 +++ linux/drivers/char/toshiba.c Fri Apr 6 10:42:55 2001 @@ -1,19 +1,24 @@ /* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops * - * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * Copyright (c) 1996-2001 Jonathan A. Buzzard (jonathan@buzzard.org.uk) * * Valuable assistance and patches from: * Tom May <tom@you-bastards.com> * Rob Napier <rnapier@employees.org> * * Fn status port numbers for machine ID's courtesy of + * 0xfc02: Scott Eisert <scott.e@sky-eye.com> + * 0xfc04: Steve VanDevender <stevev@efn.org> * 0xfc08: Garth Berry <garth@itsbruce.net> + * 0xfc0a: Egbert Eich <eich@xfree86.org> + * 0xfc10: Andrew Lofthouse <Andrew.Lofthouse@robins.af.mil> * 0xfc11: Spencer Olson <solson@novell.com> * 0xfc13: Claudius Frankewitz <kryp@gmx.de> * 0xfc15: Tom May <tom@you-bastards.com> * 0xfc17: Dave Konrad <konrad@xenia.it> * 0xfc1a: George Betzos <betzos@engr.colostate.edu> * 0xfc1d: Arthur Liu <armie@slap.mine.nu> + * 0xfcd1: Mr. Dave Konrad <konrad@xenia.it> * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * @@ -46,7 +51,7 @@ * */ -#define TOSH_VERSION "1.7 22/6/2000" +#define TOSH_VERSION "1.9 22/3/2001" #define TOSH_DEBUG 0 #include <linux/module.h> @@ -117,27 +122,6 @@ /* - * At some point we need to emulate setting the HDD auto off times for - * the new laptops. We can do this by calling the ide_ioctl on /dev/hda. - * The values we need for the various times are - * - * Disabled 0x00 - * 1 minute 0x0c - * 3 minutes 0x24 - * 5 minutes 0x3c - * 10 minutes 0x78 - * 15 minutes 0xb4 - * 20 minutes 0xf0 - * 30 minutes 0xf1 - * - */ -/*static int tosh_emulate_hdd(SMMRegisters *regs) -{ - return 0; -}*/ - - -/* * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function */ static int tosh_emulate_fan(SMMRegisters *regs) @@ -348,11 +332,12 @@ static void tosh_set_fn_port(void) { switch (tosh_id) { + case 0xfc02: case 0xfc04: case 0xfc09: case 0xfc0a: case 0xfc10: case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a: tosh_fn = 0x62; break; - case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: - case 0xfce0: case 0xfce2: + case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: case 0xfce0: + case 0xfce2: tosh_fn = 0x68; break; default: @@ -472,7 +457,6 @@ 0xa0-0xbf we can't. We just have to live dangerously and use the ports anyway, oh boy! */ - /* do we need to emulate the fan? */ if ((tosh_id==0xfccb) || (tosh_id==0xfccc)) @@ -501,7 +485,9 @@ misc_register(&tosh_device); /* register the proc entry */ + create_proc_info_entry("toshiba", 0, NULL, tosh_get_info); + return 0; } @@ -514,9 +500,11 @@ void cleanup_module(void) { /* remove the proc entry */ + remove_proc_entry("toshiba", NULL); /* unregister the device file */ + misc_deregister(&tosh_device); } #endif diff -u --recursive --new-file v2.4.3/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.3/linux/drivers/ide/ide.c Tue Mar 6 19:44:34 2001 +++ linux/drivers/ide/ide.c Wed Apr 11 19:06:12 2001 @@ -789,7 +789,11 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) { unsigned long flags; - struct request *rq = HWGROUP(drive)->rq; + struct request *rq; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + spin_unlock_irqrestore(&io_request_lock, flags); if (rq->cmd == IDE_DRIVE_CMD) { byte *args = (byte *) rq->buffer; @@ -815,10 +819,8 @@ spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - blkdev_release_request(rq); + end_that_request_last(rq); spin_unlock_irqrestore(&io_request_lock, flags); - if (rq->sem != NULL) - up(rq->sem); /* inform originator that rq has been serviced */ } /* @@ -1695,7 +1697,7 @@ unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned int major = HWIF(drive)->major; - struct list_head * queue_head; + struct list_head *queue_head = &drive->queue.queue_head; DECLARE_MUTEX_LOCKED(sem); #ifdef CONFIG_BLK_DEV_PDC4030 @@ -1708,7 +1710,6 @@ if (action == ide_wait) rq->sem = &sem; spin_lock_irqsave(&io_request_lock, flags); - queue_head = &drive->queue.queue_head; if (list_empty(queue_head) || action == ide_preempt) { if (action == ide_preempt) hwgroup->rq = NULL; diff -u --recursive --new-file v2.4.3/linux/drivers/input/joydev.c linux/drivers/input/joydev.c --- v2.4.3/linux/drivers/input/joydev.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/input/joydev.c Wed Apr 11 19:02:30 2001 @@ -1,5 +1,5 @@ /* - * $Id: joydev.c,v 1.13 2000/08/14 21:05:26 vojtech Exp $ + * $Id: joydev.c,v 1.19 2001/01/10 19:49:40 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Colin Van Dyke @@ -232,9 +232,10 @@ if (count == sizeof(struct JS_DATA_TYPE)) { struct JS_DATA_TYPE data; + int i; - data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) | - ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0); + for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) + data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; @@ -323,7 +324,7 @@ struct joydev_list *list = file->private_data; struct joydev *joydev = list->joydev; struct input_dev *dev = joydev->handle.dev; - + int i; switch (cmd) { @@ -360,6 +361,28 @@ case JSIOCGCORR: return copy_to_user((struct js_corr *) arg, joydev->corr, sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + case JSIOCSAXMAP: + if (copy_from_user((__u8 *) arg, joydev->abspam, sizeof(__u8) * ABS_MAX)) + return -EFAULT; + for (i = 0; i < ABS_MAX; i++) { + if (joydev->abspam[i] > ABS_MAX) return -EINVAL; + joydev->absmap[joydev->abspam[i]] = i; + } + return 0; + case JSIOCGAXMAP: + return copy_to_user((__u8 *) arg, joydev->abspam, + sizeof(__u8) * ABS_MAX) ? -EFAULT : 0; + case JSIOCSBTNMAP: + if (copy_from_user((__u16 *) arg, joydev->absmap, sizeof(__u16) * (KEY_MAX - BTN_MISC))) + return -EFAULT; + for (i = 0; i < KEY_MAX - BTN_MISC; i++); { + if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL; + joydev->keymap[joydev->abspam[i - BTN_MISC]] = i; + } + return 0; + case JSIOCGBTNMAP: + return copy_to_user((__u16 *) arg, joydev->keypam, + sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0; default: if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { int len; @@ -454,7 +477,7 @@ joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); - printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); +// printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); return &joydev->handle; } diff -u --recursive --new-file v2.4.3/linux/drivers/input/keybdev.c linux/drivers/input/keybdev.c --- v2.4.3/linux/drivers/input/keybdev.c Sun Mar 25 18:14:21 2001 +++ linux/drivers/input/keybdev.c Fri Apr 13 20:31:32 2001 @@ -37,7 +37,8 @@ #include <linux/module.h> #include <linux/kbd_kern.h> -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) || defined(CONFIG_SPARC64) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \ + defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) static int x86_sysrq_alt = 0; #ifdef CONFIG_SPARC64 diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.4.3/linux/drivers/isdn/Config.in Mon Mar 26 15:38:19 2001 +++ linux/drivers/isdn/Config.in Wed Apr 11 19:02:36 2001 @@ -76,8 +76,8 @@ bool ' Am7930' CONFIG_HISAX_AMD7930 fi fi - - dep_tristate ' Sedlbauer PCMCIA cs module' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA + dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA + dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA fi endmenu diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.4.3/linux/drivers/isdn/avmb1/capi.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/capi.c Wed Apr 11 19:02:30 2001 @@ -1001,6 +1001,8 @@ return -ENODEV; skb = alloc_skb(count, GFP_USER); + if (!skb) + return -ENOMEM; if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); @@ -1417,6 +1419,8 @@ return -EINVAL; skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER); + if (!skb) + return -ENOMEM; skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.4.3/linux/drivers/isdn/avmb1/capidrv.c Sun Mar 25 18:20:44 2001 +++ linux/drivers/isdn/avmb1/capidrv.c Wed Apr 11 19:02:30 2001 @@ -2069,8 +2069,8 @@ __u16 datahandle; if (!card) { - printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n", - card->contrnr, id); + printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", + id); return 0; } if (debugmode > 1) @@ -2139,8 +2139,8 @@ __u8 *p; if (!card) { - printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n", - card->contrnr, id); + printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", + id); return -ENODEV; } diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.4.3/linux/drivers/isdn/eicon/eicon_idi.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/eicon/eicon_idi.c Wed Apr 11 19:02:34 2001 @@ -2221,7 +2221,10 @@ static char *connmsg[] = {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34", "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90", - "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"}; + "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17", "V.32", "K56Flex", + "X2", "V.18", "V.18LH", "V.18HL", "V.21LH", "V.21HL", + "Bell 103LH", "Bell 103HL", "V.23", "V.23", "EDT 110", + "Baudot45", "Baudot47", "Baudot50", "DTMF" }; static u_char dtmf_code[] = { '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D' }; @@ -2243,7 +2246,11 @@ cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; - sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]); + if (p->norm > 34) { + sprintf(cmd.parm.num, "%d/(%d)", p->speed, p->norm); + } else { + sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]); + } ccard->interface.statcallb(&cmd); } eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time); diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.4.3/linux/drivers/isdn/hisax/Makefile Mon Mar 26 15:38:19 2001 +++ linux/drivers/isdn/hisax/Makefile Wed Apr 11 19:02:36 2001 @@ -54,8 +54,9 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o +obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o +obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o MD5FILES := isac.c isdnl1.c isdnl2.c isdnl3.c \ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.4.3/linux/drivers/isdn/hisax/config.c Mon Mar 26 15:38:19 2001 +++ linux/drivers/isdn/hisax/config.c Wed Apr 11 19:02:34 2001 @@ -914,13 +914,12 @@ save_flags(flags); cli(); - if (!(cs = (struct IsdnCardState *) - kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { + cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC); + if (!cs) { printk(KERN_WARNING "HiSax: No memory for IsdnCardState(card %d)\n", cardnr + 1); - restore_flags(flags); - return (0); + goto out; } memset(cs, 0, sizeof(struct IsdnCardState)); card->cs = cs; @@ -939,241 +938,235 @@ #endif cs->protocol = card->protocol; - if ((card->typ > 0) && (card->typ <= ISDN_CTYPE_COUNT)) { - if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for dlog(card %d)\n", - cardnr + 1); - restore_flags(flags); - return (0); - } - if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for status_buf(card %d)\n", - cardnr + 1); - kfree(cs->dlog); - restore_flags(flags); - return (0); - } - cs->stlist = NULL; - cs->status_read = cs->status_buf; - cs->status_write = cs->status_buf; - cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; - cs->typ = card->typ; - strcpy(cs->iif.id, id); - cs->iif.channels = 2; - cs->iif.maxbufsize = MAX_DATA_SIZE; - cs->iif.hl_hdrlen = MAX_HEADER_LEN; - cs->iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_HDLC_56K | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | + if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { + printk(KERN_WARNING + "HiSax: Card Type %d out of range\n", + card->typ); + goto outf_cs; + } + if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for dlog(card %d)\n", + cardnr + 1); + goto outf_cs; + } + if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + goto outf_dlog; + } + cs->stlist = NULL; + cs->status_read = cs->status_buf; + cs->status_write = cs->status_buf; + cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; + cs->typ = card->typ; + strcpy(cs->iif.id, id); + cs->iif.channels = 2; + cs->iif.maxbufsize = MAX_DATA_SIZE; + cs->iif.hl_hdrlen = MAX_HEADER_LEN; + cs->iif.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_HDLC_56K | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | #ifdef CONFIG_HISAX_1TR6 - ISDN_FEATURE_P_1TR6 | + ISDN_FEATURE_P_1TR6 | #endif #ifdef CONFIG_HISAX_EURO - ISDN_FEATURE_P_EURO | + ISDN_FEATURE_P_EURO | #endif #ifdef CONFIG_HISAX_NI1 - ISDN_FEATURE_P_NI1 | + ISDN_FEATURE_P_NI1 | #endif - 0; - - cs->iif.command = HiSax_command; - cs->iif.writecmd = NULL; - cs->iif.writebuf_skb = HiSax_writebuf_skb; - cs->iif.readstat = HiSax_readstatus; - register_isdn(&cs->iif); - cs->myid = cs->iif.channels; - printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, - (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : - "NONE", cs->iif.id, cs->myid); - switch (card->typ) { + 0; + + cs->iif.command = HiSax_command; + cs->iif.writecmd = NULL; + cs->iif.writebuf_skb = HiSax_writebuf_skb; + cs->iif.readstat = HiSax_readstatus; + register_isdn(&cs->iif); + cs->myid = cs->iif.channels; + printk(KERN_INFO + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, + (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "NONE", cs->iif.id, cs->myid); + switch (card->typ) { #if CARD_TELES0 - case ISDN_CTYPE_16_0: - case ISDN_CTYPE_8_0: - ret = setup_teles0(card); - break; + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + ret = setup_teles0(card); + break; #endif #if CARD_TELES3 - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_COMPAQ_ISA: - ret = setup_teles3(card); - break; + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_TELESPCMCIA: + case ISDN_CTYPE_COMPAQ_ISA: + ret = setup_teles3(card); + break; #endif #if CARD_S0BOX - case ISDN_CTYPE_S0BOX: - ret = setup_s0box(card); - break; + case ISDN_CTYPE_S0BOX: + ret = setup_s0box(card); + break; #endif #if CARD_TELESPCI - case ISDN_CTYPE_TELESPCI: - ret = setup_telespci(card); - break; + case ISDN_CTYPE_TELESPCI: + ret = setup_telespci(card); + break; #endif #if CARD_AVM_A1 - case ISDN_CTYPE_A1: - ret = setup_avm_a1(card); - break; + case ISDN_CTYPE_A1: + ret = setup_avm_a1(card); + break; #endif #if CARD_AVM_A1_PCMCIA - case ISDN_CTYPE_A1_PCMCIA: - ret = setup_avm_a1_pcmcia(card); - break; + case ISDN_CTYPE_A1_PCMCIA: + ret = setup_avm_a1_pcmcia(card); + break; #endif #if CARD_FRITZPCI - case ISDN_CTYPE_FRITZPCI: - ret = setup_avm_pcipnp(card); - break; + case ISDN_CTYPE_FRITZPCI: + ret = setup_avm_pcipnp(card); + break; #endif #if CARD_ELSA - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_ELSA_PCI: - ret = setup_elsa(card); - break; + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_PNP: + case ISDN_CTYPE_ELSA_PCMCIA: + case ISDN_CTYPE_ELSA_PCI: + ret = setup_elsa(card); + break; #endif #if CARD_IX1MICROR2 - case ISDN_CTYPE_IX1MICROR2: - ret = setup_ix1micro(card); - break; + case ISDN_CTYPE_IX1MICROR2: + ret = setup_ix1micro(card); + break; #endif #if CARD_DIEHLDIVA - case ISDN_CTYPE_DIEHLDIVA: - ret = setup_diva(card); - break; + case ISDN_CTYPE_DIEHLDIVA: + ret = setup_diva(card); + break; #endif #if CARD_ASUSCOM - case ISDN_CTYPE_ASUSCOM: - ret = setup_asuscom(card); - break; + case ISDN_CTYPE_ASUSCOM: + ret = setup_asuscom(card); + break; #endif #if CARD_TELEINT - case ISDN_CTYPE_TELEINT: - ret = setup_TeleInt(card); - break; + case ISDN_CTYPE_TELEINT: + ret = setup_TeleInt(card); + break; #endif #if CARD_SEDLBAUER - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - case ISDN_CTYPE_SEDLBAUER_FAX: - ret = setup_sedlbauer(card); - break; + case ISDN_CTYPE_SEDLBAUER: + case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: + ret = setup_sedlbauer(card); + break; #endif #if CARD_SPORTSTER - case ISDN_CTYPE_SPORTSTER: - ret = setup_sportster(card); - break; + case ISDN_CTYPE_SPORTSTER: + ret = setup_sportster(card); + break; #endif #if CARD_MIC - case ISDN_CTYPE_MIC: - ret = setup_mic(card); - break; + case ISDN_CTYPE_MIC: + ret = setup_mic(card); + break; #endif #if CARD_NETJET_S - case ISDN_CTYPE_NETJET_S: - ret = setup_netjet_s(card); - break; + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); + break; #endif #if CARD_HFCS - case ISDN_CTYPE_TELES3C: - case ISDN_CTYPE_ACERP10: - ret = setup_hfcs(card); - break; + case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_ACERP10: + ret = setup_hfcs(card); + break; #endif #if CARD_HFC_PCI - case ISDN_CTYPE_HFC_PCI: - ret = setup_hfcpci(card); - break; + case ISDN_CTYPE_HFC_PCI: + ret = setup_hfcpci(card); + break; #endif #if CARD_HFC_SX - case ISDN_CTYPE_HFC_SX: - ret = setup_hfcsx(card); - break; + case ISDN_CTYPE_HFC_SX: + ret = setup_hfcsx(card); + break; #endif #if CARD_NICCY - case ISDN_CTYPE_NICCY: - ret = setup_niccy(card); - break; + case ISDN_CTYPE_NICCY: + ret = setup_niccy(card); + break; #endif #if CARD_AMD7930 - case ISDN_CTYPE_AMD7930: - ret = setup_amd7930(card); - break; + case ISDN_CTYPE_AMD7930: + ret = setup_amd7930(card); + break; #endif #if CARD_ISURF - case ISDN_CTYPE_ISURF: - ret = setup_isurf(card); - break; + case ISDN_CTYPE_ISURF: + ret = setup_isurf(card); + break; #endif #if CARD_HSTSAPHIR - case ISDN_CTYPE_HSTSAPHIR: - ret = setup_saphir(card); - break; + case ISDN_CTYPE_HSTSAPHIR: + ret = setup_saphir(card); + break; #endif #if CARD_TESTEMU - case ISDN_CTYPE_TESTEMU: - ret = setup_testemu(card); - break; + case ISDN_CTYPE_TESTEMU: + ret = setup_testemu(card); + break; #endif #if CARD_BKM_A4T - case ISDN_CTYPE_BKM_A4T: - ret = setup_bkm_a4t(card); - break; + case ISDN_CTYPE_BKM_A4T: + ret = setup_bkm_a4t(card); + break; #endif #if CARD_SCT_QUADRO - case ISDN_CTYPE_SCT_QUADRO: - ret = setup_sct_quadro(card); - break; + case ISDN_CTYPE_SCT_QUADRO: + ret = setup_sct_quadro(card); + break; #endif #if CARD_GAZEL - case ISDN_CTYPE_GAZEL: - ret = setup_gazel(card); - break; + case ISDN_CTYPE_GAZEL: + ret = setup_gazel(card); + break; #endif #if CARD_W6692 - case ISDN_CTYPE_W6692: - ret = setup_w6692(card); - break; + case ISDN_CTYPE_W6692: + ret = setup_w6692(card); + break; #endif #if CARD_NETJET_U - case ISDN_CTYPE_NETJET_U: - ret = setup_netjet_u(card); - break; -#endif - default: - printk(KERN_WARNING - "HiSax: Support for %s Card not selected\n", - CardType[card->typ]); - ll_unload(cs); - restore_flags(flags); - return (0); - } - } else { + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; +#endif + default: printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", - card->typ); - restore_flags(flags); - return (0); + "HiSax: Support for %s Card not selected\n", + CardType[card->typ]); + ll_unload(cs); + goto outf_cs; } if (!ret) { ll_unload(cs); - restore_flags(flags); - return (0); + goto outf_cs; } if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n"); - return (1); + ll_unload(cs); + goto outf_cs; } cs->rcvidx = 0; cs->tx_skb = NULL; @@ -1190,21 +1183,31 @@ ret = init_card(cs); if (ret) { closecard(cardnr); - restore_flags(flags); - return (0); + ret = 0; + goto outf_cs; } init_tei(cs, cs->protocol); ret = CallcNewChan(cs); if (ret) { closecard(cardnr); - restore_flags(flags); - return 0; + ret = 0; + goto outf_cs; } /* ISAR needs firmware download first */ if (!test_bit(HW_ISAR, &cs->HW_Flags)) ll_run(cs, 0); + + ret = 1; + goto out; + + outf_dlog: + kfree(cs->dlog); + outf_cs: + kfree(cs); + card->cs = NULL; + out: restore_flags(flags); - return (1); + return ret; } void __devinit @@ -1253,9 +1256,6 @@ } else { printk(KERN_WARNING "HiSax: Card %s not installed !\n", CardType[cards[i].typ]); - if (cards[i].cs) - kfree((void *) cards[i].cs); - cards[i].cs = NULL; HiSax_shiftcards(i); nrcards--; } diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/elsa_cs.c linux/drivers/isdn/hisax/elsa_cs.c --- v2.4.3/linux/drivers/isdn/hisax/elsa_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/elsa_cs.c Wed Apr 11 19:02:34 2001 @@ -0,0 +1,558 @@ +/*====================================================================== + + An elsa_cs PCMCIA client driver + + This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus + Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved. + +======================================================================*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ds.h> +#include <pcmcia/bus_ops.h> + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"elsa_cs.c $Revision: 3.0 $ $Date: 2001/03/10 10:00:23 $ (K.Lichtenwalder)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from, the old way */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, 3 */ +static u_long irq_mask = 0xdeb8; + +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +static int protocol = 2; /* EURO-ISDN Default */ +MODULE_PARM(protocol, "i"); + +extern int elsa_init_pcmcia(int, int, int*, int); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the elsa_cs event + handler. +*/ + +static void elsa_cs_config(dev_link_t *link); +static void elsa_cs_release(u_long arg); +static int elsa_cs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *elsa_cs_attach(void); +static void elsa_cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "elsa_cs"; + +/* + A linked list of "instances" of the elsa_cs device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + To simplify the data structure handling, we actually include the + dev_link_t structure in the device's private data structure. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. + + The bus_operations pointer is used on platforms for which we need + to use special socket-specific versions of normal IO primitives + (inb, outb, readb, writeb, etc) for card IO. +*/ + +typedef struct local_info_t { + dev_link_t link; + dev_node_t node; + int busy; + struct bus_operations *bus; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret}; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + elsa_cs_attach() creates an "instance" of the driver, allocatingx + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *elsa_cs_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + void elsa_interrupt(int, void *, struct pt_regs *); + + DEBUG(0, "elsa_cs_attach()\n"); + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) return NULL; + memset(local, 0, sizeof(local_info_t)); + link = &local->link; link->priv = local; + + /* Initialize the dev_link_t structure */ + link->release.function = &elsa_cs_release; + link->release.data = (u_long)link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID|IRQ_SHARE_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 3; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &elsa_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + elsa_cs_detach(link); + return NULL; + } + + return link; +} /* elsa_cs_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void elsa_cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + local_info_t *info = link->priv; + int ret; + + DEBUG(0, "elsa_cs_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + elsa_cs_release((u_long)link); + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { + DEBUG(0, "elsa_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure and free it */ + *linkp = link->next; + kfree(info); + +} /* elsa_cs_detach */ + +/*====================================================================== + + elsa_cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) return i; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +static void elsa_cs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + local_info_t *dev; + int i, j, last_fn; + u_short buf[128]; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + + DEBUG(0, "elsa_config(0x%p)\n", link); + handle = link->handle; + dev = link->priv; + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 255; + tuple.TupleOffset = 0; + tuple.Attributes = 0; + i = first_tuple(handle, &tuple, &parse); + if (i != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if ( (cf->io.nwin > 0) && cf->io.win[0].base) { + printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } else { + printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); + link->conf.ConfigIndex = cf->index; + for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { + link->io.BasePort1 = j; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + last_fn = RequestIO; + goto cs_failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + link->irq.AssignedIRQ = 0; + last_fn = RequestIRQ; + goto cs_failed; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + last_fn = RequestConfiguration; + goto cs_failed; + } + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. *//* */ + sprintf(dev->node.dev_name, "elsa"); + dev->node.major = dev->node.minor = 0x0; + + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + + elsa_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ, + &(((local_info_t*)link->priv)->busy), + protocol); + return; +cs_failed: + cs_error(link->handle, last_fn, i); + elsa_cs_release((u_long)link); +} /* elsa_cs_config */ + +/*====================================================================== + + After a card is removed, elsa_cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void elsa_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "elsa_cs_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(1, "elsa_cs: release postponed, '%s' " + "still open\n", link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + if (link->win) + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + elsa_cs_detach(link); + +} /* elsa_cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int elsa_cs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *dev = link->priv; + + DEBUG(1, "elsa_cs_event(%d)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((local_info_t*)link->priv)->busy = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dev->bus = args->bus; + elsa_cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + dev->busy = 1; + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + dev->busy = 0; + break; + } + return 0; +} /* elsa_cs_event */ + +/*====================================================================*/ + +static int __init init_elsa_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "elsa_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach); + return 0; +} + +static void __exit exit_elsa_cs(void) +{ + DEBUG(0, "elsa_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + elsa_cs_detach(dev_list); +} + +module_init(init_elsa_cs); +module_exit(exit_elsa_cs); diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.4.3/linux/drivers/isdn/hisax/isar.c Fri Mar 2 11:12:09 2001 +++ linux/drivers/isdn/hisax/isar.c Wed Apr 11 19:02:35 2001 @@ -383,12 +383,12 @@ } else { printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n", ireg->cmsb, ireg->clsb, ireg->par[0]); - ret = 1;goto reterror; + ret = 1;goto reterrflg; } ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { printk(KERN_ERR"isar RQST SVN failed\n"); - ret = 1;goto reterror; + ret = 1;goto reterrflg; } cnt = 30000; /* max 300 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.4.3/linux/drivers/isdn/isdn_common.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/isdn/isdn_common.c Wed Apr 11 19:02:35 2001 @@ -312,7 +312,7 @@ void isdn_timer_ctrl(int tf, int onoff) { - int flags; + int flags, old_tflags; save_flags(flags); cli(); @@ -321,11 +321,12 @@ isdn_timer_cnt1 = 0; isdn_timer_cnt2 = 0; } + old_tflags = dev->tflags; if (onoff) dev->tflags |= tf; else dev->tflags &= ~tf; - if (dev->tflags) + if (dev->tflags && !old_tflags) mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES); restore_flags(flags); } @@ -1026,7 +1027,7 @@ retval = -ENODEV; goto out; } - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) { @@ -1119,7 +1120,7 @@ return -ENODEV; lock_kernel(); - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) { @@ -1272,7 +1273,7 @@ } if (!dev->drivers) return -ENODEV; - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; @@ -1687,7 +1688,7 @@ } if (!dev->channels) goto out; - if (minor < ISDN_MINOR_CTRL) { + if (minor <= ISDN_MINOR_BMAX) { printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) @@ -1747,7 +1748,7 @@ goto out; } isdn_unlock_drivers(); - if (minor < ISDN_MINOR_CTRL) + if (minor <= ISDN_MINOR_BMAX) goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.4.3/linux/drivers/isdn/isdn_ppp.c Thu Feb 8 10:40:25 2001 +++ linux/drivers/isdn/isdn_ppp.c Wed Apr 11 19:02:36 2001 @@ -165,6 +165,7 @@ int unit = 0; long flags; struct ippp_struct *is; + int retval; save_flags(flags); cli(); @@ -197,12 +198,14 @@ if (i >= ISDN_MAX_CHANNELS) { restore_flags(flags); printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); - return -1; + retval = -1; + goto out; } unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ if (unit < 0) { printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name); - return -1; + retval = -1; + goto out; } lp->ppp_slot = i; @@ -211,13 +214,16 @@ is->unit = unit; is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ #ifdef CONFIG_ISDN_MPP - if (isdn_ppp_mp_init(lp, NULL) < 0) - return -ENOMEM; + retval = isdn_ppp_mp_init(lp, NULL); + if (retval < 0) + goto out; #endif /* CONFIG_ISDN_MPP */ - restore_flags(flags); + retval = lp->ppp_slot; - return lp->ppp_slot; + out: + restore_flags(flags); + return retval; } /* @@ -2431,6 +2437,13 @@ switch(skb->data[0]) { case CCP_CONFREQ: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable compression here!\n"); + if(proto == PPP_CCP) + mis->compflags &= ~SC_COMP_ON; + else + is->compflags &= ~SC_LINK_COMP_ON; + break; case CCP_TERMREQ: case CCP_TERMACK: if(is->debug & 0x10) @@ -2546,6 +2559,17 @@ /* TODO: Clean this up with new Reset semantics */ +/* I believe the CCP handling as-is is done wrong. Compressed frames + * should only be sent/received after CCP reaches UP state, which means + * both sides have sent CONF_ACK. Currently, we handle both directions + * independently, which means we may accept compressed frames too early + * (supposedly not a problem), but may also mean we send compressed frames + * too early, which may turn out to be a problem. + * This part of state machine should actually be handled by (i)pppd, but + * that's too big of a change now. --kai + */ + + static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) { struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot]; @@ -2580,6 +2604,13 @@ switch(data[2]) { case CCP_CONFREQ: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable decompression here!\n"); + if(proto == PPP_CCP) + is->compflags &= ~SC_DECOMP_ON; + else + is->compflags &= ~SC_LINK_DECOMP_ON; + break; case CCP_TERMREQ: case CCP_TERMACK: if(is->debug & 0x10) diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.4.3/linux/drivers/isdn/pcbit/drv.c Fri Mar 2 11:12:09 2001 +++ linux/drivers/isdn/pcbit/drv.c Wed Apr 11 19:02:36 2001 @@ -412,7 +412,6 @@ return len; } - int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel) { struct pcbit_dev * dev; @@ -436,32 +435,36 @@ if (len > BANK4 + 1) { printk("pcbit_writecmd: invalid length %d\n", len); - return -EFAULT; + return -EINVAL; } if (user) { - u_char cbuf[1024]; + u_char *cbuf = kmalloc(len, GFP_KERNEL); + if (!cbuf) + return -ENOMEM; - copy_from_user(cbuf, buf, len); - for (i=0; i<len; i++) - writeb(cbuf[i], dev->sh_mem + i); + if (copy_from_user(cbuf, buf, len)) { + kfree(cbuf); + return -EFAULT; + } + memcpy_toio(dev->sh_mem, cbuf, len); + kfree(cbuf); } else memcpy_toio(dev->sh_mem, buf, len); return len; - break; case L2_FWMODE: /* this is the hard part */ /* dumb board */ - if (len < 0) - return -EINVAL; - if (user) { /* get it into kernel space */ if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) return -ENOMEM; - copy_from_user(ptr, buf, len); + if (copy_from_user(ptr, buf, len)) { + kfree(ptr); + return -EFAULT; + } loadbuf = ptr; } else @@ -493,12 +496,9 @@ kfree(ptr); return errstat ? errstat : len; - - break; default: return -EBUSY; } - return 0; } /* diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c --- v2.4.3/linux/drivers/isdn/sc/interrupt.c Mon Mar 26 15:38:19 2001 +++ linux/drivers/isdn/sc/interrupt.c Wed Apr 11 19:02:36 2001 @@ -34,7 +34,6 @@ extern int indicate_status(int, int, ulong, char *); extern void check_phystat(unsigned long); -extern void dump_messages(int); extern int receivemessage(int, RspMessage *); extern int sendmessage(int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); diff -u --recursive --new-file v2.4.3/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c --- v2.4.3/linux/drivers/isdn/sc/message.c Sun Nov 7 16:34:00 1999 +++ linux/drivers/isdn/sc/message.c Wed Apr 11 19:02:36 2001 @@ -38,55 +38,12 @@ extern unsigned int cinst; /* - * Obligitory function prototypes + * Obligatory function prototypes */ extern int indicate_status(int,ulong,char*); extern int scm_command(isdn_ctrl *); extern void *memcpy_fromshmem(int, void *, const void *, size_t); -/* - * Dump message queue in shared memory to screen - */ -void dump_messages(int card) -{ - DualPortMemory dpm; - unsigned long flags; - - int i =0; - - if (!IS_VALID_CARD(card)) { - pr_debug("Invalid param: %d is not a valid card id\n", card); - } - - save_flags(flags); - cli(); - outb(adapter[card]->ioport[adapter[card]->shmem_pgport], - (adapter[card]->shmem_magic >> 14) | 0x80); - memcpy_fromshmem(card, &dpm, 0, sizeof(dpm)); - restore_flags(flags); - - pr_debug("%s: Dumping Request Queue\n", adapter[card]->devicename); - for (i = 0; i < dpm.req_head; i++) { - pr_debug("%s: Message #%d: (%d,%d,%d), link: %d\n", - adapter[card]->devicename, i, - dpm.req_queue[i].type, - dpm.req_queue[i].class, - dpm.req_queue[i].code, - dpm.req_queue[i].phy_link_no); - } - - pr_debug("%s: Dumping Response Queue\n", adapter[card]->devicename); - for (i = 0; i < dpm.rsp_head; i++) { - pr_debug("%s: Message #%d: (%d,%d,%d), link: %d, status: %d\n", - adapter[card]->devicename, i, - dpm.rsp_queue[i].type, - dpm.rsp_queue[i].class, - dpm.rsp_queue[i].code, - dpm.rsp_queue[i].phy_link_no, - dpm.rsp_queue[i].rsp_status); - } - -} /* * receive a message from the board diff -u --recursive --new-file v2.4.3/linux/drivers/md/lvm.c linux/drivers/md/lvm.c --- v2.4.3/linux/drivers/md/lvm.c Sun Jan 28 16:11:20 2001 +++ linux/drivers/md/lvm.c Thu Apr 12 12:16:35 2001 @@ -148,6 +148,9 @@ * procfs is always supported now. (JT) * 12/01/2001 - avoided flushing logical volume in case of shrinking * because of unecessary overhead in case of heavy updates + * 05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it + * destroys stacking devices. call b_end_io on failed maps. + * (Jens Axboe) * */ @@ -163,13 +166,6 @@ #include <linux/config.h> #include <linux/version.h> - -#ifdef MODVERSIONS -#undef MODULE -#define MODULE -#include <linux/modversions.h> -#endif - #include <linux/module.h> #include <linux/kernel.h> @@ -1480,14 +1476,14 @@ */ static int lvm_map(struct buffer_head *bh, int rw) { - int minor = MINOR(bh->b_dev); + int minor = MINOR(bh->b_rdev); int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_blocknr * size; + ulong rsector_tmp = bh->b_rsector; ulong rsector_sav; - kdev_t rdev_tmp = bh->b_dev; + kdev_t rdev_tmp = bh->b_rdev; kdev_t rdev_sav; vg_t *vg_this = vg[VG_BLK(minor)]; lv_t *lv = vg_this->lv[LV_BLK(minor)]; @@ -1676,8 +1672,12 @@ */ static int lvm_make_request_fn(request_queue_t *q, int rw, - struct buffer_head *bh) { - return (lvm_map(bh, rw) < 0) ? 0 : 1; + struct buffer_head *bh) +{ + int ret = lvm_map(bh, rw); + if (ret < 0) + buffer_IO_error(bh); + return ret; } diff -u --recursive --new-file v2.4.3/linux/drivers/md/md.c linux/drivers/md/md.c --- v2.4.3/linux/drivers/md/md.c Mon Mar 12 18:13:28 2001 +++ linux/drivers/md/md.c Fri Apr 6 10:42:55 2001 @@ -1063,10 +1063,10 @@ } printk(".\n"); if (err) { - printk("errors occured during superblock update, repeating\n"); + printk("errors occurred during superblock update, repeating\n"); if (--count) goto repeat; - printk("excessive errors occured during superblock update, exiting\n"); + printk("excessive errors occurred during superblock update, exiting\n"); } return 0; } diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in --- v2.4.3/linux/drivers/media/radio/Config.in Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/Config.in Fri Apr 13 20:26:07 2001 @@ -23,7 +23,7 @@ fi dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV -dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV +dep_tristate ' miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile --- v2.4.3/linux/drivers/media/radio/Makefile Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/Makefile Fri Apr 13 20:26:07 2001 @@ -23,7 +23,9 @@ export-objs := -list-multi := +list-multi := miropcm20.o + +miropcm20-objs := radio-miropcm20.o rds-miropcm20.o obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o @@ -34,9 +36,12 @@ obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o +obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o include $(TOPDIR)/Rules.make + +miropcm20.o: $(miropcm20-objs) + $(LD) -r -o $@ $(miropcm20-objs) diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c --- v2.4.3/linux/drivers/media/radio/radio-miropcm20.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/radio/radio-miropcm20.c Fri Apr 13 20:26:07 2001 @@ -2,62 +2,53 @@ * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> * Thanks to Norberto Pellici for the ACI device interface specification * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c) + * This driver relies on the aci mixer (drivers/sound/aci.c) * Look there for further info... */ -#include <linux/module.h> /* Modules */ -#include <linux/init.h> /* Initdata */ -#include <asm/uaccess.h> /* copy to/from user */ -#include <linux/videodev.h> /* kernel radio structs */ -#include "../../sound/miroaci.h" /* ACI Control by acimixer */ +/* Revision history: + * + * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> + * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de> + * removed unfinished volume control (maybe adding it later again) + * use OSS-mixer; added stereo control + */ + +/* What ever you think about the ACI, version 0x07 is not very well! + * I cant get frequency, 'tuner status', 'tuner flags' or mute/mono + * conditions... Robert + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/videodev.h> +#include <linux/devfs_fs_kernel.h> +#include <asm/uaccess.h> + +char * aci_radio_name; + +#include "../../sound/aci.h" static int users = 0; struct pcm20_device { - int port; - int curvol; - unsigned long curfreq; + unsigned long freq; int muted; + int stereo; }; -/* local things */ - - -static void pcm20_mute(struct pcm20_device *dev) +static int pcm20_mute(struct pcm20_device *dev, unsigned char mute) { - - dev->muted = 1; - aci_write_cmd(0xa3,0x01); - + dev->muted = mute; + return aci_write_cmd(0xa3, mute); } -static int pcm20_setvol(struct pcm20_device *dev, int vol) +static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo) { - - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - aci_write_cmd(0xa3,0x00); /* enable card */ - } - - return 0; - } - - if(vol == 0) { /* volume = 0 means mute the card */ - aci_write_cmd(0x3d, 0x20); - aci_write_cmd(0x35, 0x20); - return 0; - } - - dev->muted = 0; - aci_write_cmd(0x3d, 32-vol); /* Right Channel */ - aci_write_cmd(0x35, 32-vol); /* Left Channel */ - dev->curvol = vol; - - return 0; + dev->stereo = stereo; + return aci_write_cmd(0xa4, !stereo); } static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) @@ -65,28 +56,79 @@ unsigned char freql; unsigned char freqh; - freq = (freq * 10) / 16; - freql = freq & 0xff; - freqh = freq >> 8; + dev->freq=freq; + freq /= 160; + if (!(aci_version==0x07 || aci_version>=0xb0)) + freq /= 10; /* I don't know exactly which version + * needs this hack */ + freql = freq & 0xff; + freqh = freq >> 8; - aci_write_cmd_d(0xa7, freql, freqh); /* Tune to frequency */ + aci_rds_cmd(RDS_RESET, 0, 0); + pcm20_stereo(dev, 1); - return 0; + return aci_rw_cmd(0xa7, freql, freqh); /* Tune to frequency */ } -int pcm20_getsigstr(struct pcm20_device *dev) +static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal) { + /* okay, check for signal, stereo and rds here... */ + int i; unsigned char buf; - aci_indexed_cmd(0xf0, 0x32, &buf); - if ((buf & 0x80) == 0x80) + + if ((i=aci_rw_cmd(0xa9, -1, -1))<0) + return i; +#if DEBUG + printk("check_sig: 0x%x\n", i); +#endif + if (i & 0x80) { + /* no signal from tuner */ + *flags=0; + *signal=0; + return 0; + } else + *signal=0xffff; + + if ((i=aci_rw_cmd(0xa8, -1, -1))<0) + return i; + if (i & 0x40) { + *flags=0; + } else { + /* stereo */ + *flags=VIDEO_TUNER_STEREO_ON; + /* I cant see stereo, when forced to mono */ + dev->stereo=1; + } + + if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0) + return i; + if (buf & 1) + /* RDS available */ + *flags|=VIDEO_TUNER_RDS_ON; + else return 0; - return 1; /* signal present */ + + if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) + return i; +#if DEBUG + printk("rds-signal: %d\n", buf); +#endif + if (buf > 15) { + printk("rds-miropcm20: RX strengths unexpected high...\n"); + buf=15; + } + /* refine signal */ + if ((*signal=SCALE(15, 0xffff, buf))==0) + *signal = 1; + + return 0; } static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct pcm20_device *pcm20=dev->priv; + int i; switch(cmd) { @@ -113,11 +155,11 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(int)(87.5*16); - v.rangehigh=(int)(108.0*16); - v.flags=0; + v.rangelow=87*16000; + v.rangehigh=108*16000; + pcm20_getflags(pcm20, &v.flags, &v.signal); + v.flags|=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*pcm20_getsigstr(pcm20); strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; @@ -134,20 +176,28 @@ return 0; } case VIDIOCGFREQ: - if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq))) + if(copy_to_user(arg, &pcm20->freq, sizeof(pcm20->freq))) return -EFAULT; return 0; case VIDIOCSFREQ: - if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq))) + if(copy_from_user(&pcm20->freq, arg, sizeof(pcm20->freq))) return -EFAULT; - pcm20_setfreq(pcm20, pcm20->curfreq); - return 0; + i=pcm20_setfreq(pcm20, pcm20->freq); +#if DEBUG + printk("First view (setfreq): 0x%x\n", i); +#endif + return i; case VIDIOCGAUDIO: { struct video_audio v; memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - v.volume=pcm20->curvol * 2048; + v.flags=VIDEO_AUDIO_MUTABLE; + if (pcm20->muted) + v.flags|=VIDEO_AUDIO_MUTE; + v.mode=VIDEO_SOUND_STEREO; + if (pcm20->stereo) + v.mode|=VIDEO_SOUND_MONO; + /* v.step=2048; */ strcpy(v.name, "Radio"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; @@ -157,14 +207,15 @@ { struct video_audio v; if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; + return -EFAULT; if(v.audio) return -EINVAL; - if(v.flags&VIDEO_AUDIO_MUTE) - pcm20_mute(pcm20); - else - pcm20_setvol(pcm20,v.volume/2048); + pcm20_mute(pcm20, !!(v.flags&VIDEO_AUDIO_MUTE)); + if(v.flags&VIDEO_SOUND_MONO) + pcm20_stereo(pcm20, 0); + if(v.flags&VIDEO_SOUND_STEREO) + pcm20_stereo(pcm20, 1); return 0; } @@ -186,7 +237,12 @@ users--; } -static struct pcm20_device pcm20_unit; +static struct pcm20_device pcm20_unit= +{ + freq: 87*16000, + muted: 1, + stereo: 0 +}; static struct video_device pcm20_radio= { @@ -197,24 +253,23 @@ open: pcm20_open, close: pcm20_close, ioctl: pcm20_ioctl, + priv: &pcm20_unit }; static int __init pcm20_init(void) { - - pcm20_radio.priv=&pcm20_unit; - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1) return -EINVAL; + if(attach_aci_rds()<0) { + video_unregister_device(&pcm20_radio); + return -EINVAL; + } +#if DEBUG + printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0)); +#endif printk(KERN_INFO "Miro PCM20 radio card driver.\n"); - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - - pcm20_unit.curvol = 0; - return 0; } @@ -225,9 +280,9 @@ static void __exit pcm20_cleanup(void) { + unload_aci_rds(); video_unregister_device(&pcm20_radio); } module_init(pcm20_init); module_exit(pcm20_cleanup); - diff -u --recursive --new-file v2.4.3/linux/drivers/media/radio/rds-miropcm20.c linux/drivers/media/radio/rds-miropcm20.c --- v2.4.3/linux/drivers/media/radio/rds-miropcm20.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/rds-miropcm20.c Fri Apr 13 20:26:07 2001 @@ -0,0 +1,249 @@ +/* + * Many thanks to Fred Seidel <seidel@metabox.de>, the + * designer of the RDS decoder hardware. With his help + * I was able to code this driver. + * Thanks also to Norberto Pellicci, Dominic Mounteney + * <DMounteney@pinnaclesys.com> and www.teleauskunft.de + * for good hints on finding Fred. It was somewhat hard + * to locate him here in Germany... [: + * + * Revision history: + * + * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de> + * RDS support for MiroSound PCM20 radio + */ + +#define _NO_VERSION_ + +/* #include <linux/kernel.h> */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include "../../sound/aci.h" + +#define WATCHMASK 0352 /* 11101010 */ + +#define DEBUG 0 + +static struct semaphore aci_rds_sem; + + +#define RDS_BUSYMASK 0x10 /* Bit 4 */ +#define RDS_CLOCKMASK 0x08 /* Bit 3 */ +#define RDS_DATAMASK 0x04 /* Bit 2 */ + + +static void print_matrix(char array[], unsigned int length) +{ + int i, j; + + for (i=0; i<length; i++) { + printk("aci-rds: "); + for (j=7; j>=0; j--) { + printk("%d", (array[i] >> j) & 0x1); + } + if (i%8 == 0) + printk(" byte-border\n"); + else + printk("\n"); + } +} + +static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size) +{ + int i; + + if (size != 8) + return -1; + for (i = 7; i >= 0; i--) + sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0; + sendbuffer[0] |= RDS_CLOCKMASK; + + return 0; +} + +static int trans2byte(unsigned char buffer[], int size) +{ + int i; + unsigned char byte=0; + + if (size != 8) + return -1; + for (i = 7; i >= 0; i--) + byte |= ((buffer[7-i] & RDS_DATAMASK) ? 1 : 0) << i; + + return byte; +} + +static int trans2data(unsigned char readbuffer[], int readsize, unsigned char data[], int datasize) +{ + int i,j; + + if (readsize != datasize*8) + return -1; + for (i = 0; i < datasize; i++) + if ((j=trans2byte(&readbuffer[i*8], 8)) < 0) + return -1; + else + data[i]=j; + return 0; +} + +static int rds_waitread(void) +{ + unsigned char byte; + int i=2000; + + do { + byte=inb(RDS_REGISTER); + if ((byte & WATCHMASK) != WATCHMASK) + printk("aci-rds: Hidden information discoverd!\n"); + i--; + } + while ((byte & RDS_BUSYMASK) && i); + + if (i) { +#if DEBUG + printk("rds_waitread()"); + print_matrix(&byte, 1); +#endif + return (byte); + } else { + printk("aci-rds: rds_waitread() timeout...\n"); + return -1; + } +} + +/* dont use any ..._nowait() function if you are not sure what you do... */ + +static inline void rds_rawwrite_nowait(unsigned char byte) +{ +#if DEBUG + printk("rds_rawwrite()"); + print_matrix(&byte, 1); +#endif + outb(byte, RDS_REGISTER); +} + +static int rds_rawwrite(unsigned char byte) +{ + if (rds_waitread() >= 0) { + rds_rawwrite_nowait(byte); + return 0; + } else + return -1; +} + +static int rds_write(unsigned char cmd) +{ + unsigned char sendbuffer[8]; + int i; + + if (byte2trans(cmd, sendbuffer, 8) != 0){ + return -1; + } else { + for (i=0; i<8; i++) { + rds_rawwrite(sendbuffer[i]); + } + } + return 0; +} + +static int rds_readcycle_nowait(void) +{ + rds_rawwrite_nowait(0); + return rds_waitread(); +} + +static int rds_readcycle(void) +{ + if (rds_rawwrite(0) < 0) + return -1; + return rds_waitread(); +} + +static int rds_read(unsigned char databuffer[], int datasize) +{ + +#define READSIZE (8*datasize) + + int i,j; + unsigned char* readbuffer; + + if (!datasize) /* nothing to read */ + return 0; + + /* to be able to use rds_readcycle_nowait() + I have to readwait() here */ + if (rds_waitread() < 0) + return -1; + + if ((readbuffer=kmalloc(READSIZE, GFP_KERNEL)) == 0) { + printk("aci-rds: Out of memory...\n"); + return -ENOMEM; + } else { + if (signal_pending(current)) { + kfree(readbuffer); + return -EINTR; + } + } + + for (i=0; i< READSIZE; i++) + if((j=rds_readcycle_nowait()) < 0) { + kfree(readbuffer); + return -1; + } else + readbuffer[i]=j; + if (trans2data(readbuffer, READSIZE, databuffer, datasize) < 0) { + kfree(readbuffer); + return -1; + } + kfree(readbuffer); + return 0; +} + +static int rds_ack(void) +{ + int i=rds_readcycle(); + + if (i < 0) + return -1; + if (i & RDS_DATAMASK) { + return 0; /* ACK */ + } else { + return 1; /* NACK */ + } +} + +int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize) +{ + int ret; + + if (down_interruptible(&aci_rds_sem)) + return -EINTR; + + if (rds_write(cmd)) + ret = -2; + + /* RDS_RESET doesn't need further processing */ + if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize))) + ret = -1; + else + ret = 0; + + up(&aci_rds_sem); + + return ret; +} + +int __init attach_aci_rds(void) +{ + init_MUTEX(&aci_rds_sem); + return 0; +} + +void __exit unload_aci_rds(void) +{ +} diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c --- v2.4.3/linux/drivers/media/video/bttv-cards.c Mon Feb 19 14:43:36 2001 +++ linux/drivers/media/video/bttv-cards.c Wed Apr 11 19:02:36 2001 @@ -1404,7 +1404,7 @@ bits_out = (PT2254_DBS_IN_2>>(vol%5)); /* tens */ bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; data = btread(BT848_GPIO_DATA); data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| WINVIEW_PT2254_STROBE); diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h --- v2.4.3/linux/drivers/media/video/bttv.h Tue Mar 6 19:44:34 2001 +++ linux/drivers/media/video/bttv.h Wed Apr 11 19:02:36 2001 @@ -91,8 +91,8 @@ #define I2C_DPL3518 0x84 /* more card-specific defines */ -#define PT2254_L_CHANEL 0x10 -#define PT2254_R_CHANEL 0x08 +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 #define PT2254_DBS_IN_2 0x400 #define PT2254_DBS_IN_10 0x20000 #define WINVIEW_PT2254_CLK 0x40 diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- v2.4.3/linux/drivers/media/video/cpia.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/cpia.c Fri Apr 6 10:42:55 2001 @@ -2832,7 +2832,7 @@ DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame, vm.width, vm.height); #endif - if (vm.frame<0||vm.frame>FRAME_NUM) { + if (vm.frame<0||vm.frame>=FRAME_NUM) { retval = -EINVAL; break; } diff -u --recursive --new-file v2.4.3/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c --- v2.4.3/linux/drivers/media/video/stradis.c Fri Mar 2 11:12:10 2001 +++ linux/drivers/media/video/stradis.c Fri Apr 6 10:42:55 2001 @@ -54,8 +54,8 @@ #include "cs8420.h" #define DEBUG(x) /* debug driver */ -#undef IDEBUG(x) /* debug irq handler */ -#undef MDEBUG(x) /* debug memory management */ +#undef IDEBUG /* debug irq handler */ +#undef MDEBUG /* debug memory management */ #define SAA7146_MAX 6 diff -u --recursive --new-file v2.4.3/linux/drivers/mtd/pmc551.c linux/drivers/mtd/pmc551.c --- v2.4.3/linux/drivers/mtd/pmc551.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/mtd/pmc551.c Fri Apr 6 10:42:55 2001 @@ -13,17 +13,17 @@ * * Description: * This driver is intended to support the PMC551 PCI Ram device from - * Ramix Inc. The PMC551 is a PMC Mezzanine module for cPCI embeded + * Ramix Inc. The PMC551 is a PMC Mezzanine module for cPCI embedded * systems. The device contains a single SROM that initally programs the * V370PDC chipset onboard the device, and various banks of DRAM/SDRAM * onboard. This driver implements this PCI Ram device as an MTD (Memory * Technologies Device) so that it can be used to hold a filesystem, or - * for added swap space in embeded systems. Since the memory on this + * for added swap space in embedded systems. Since the memory on this * board isn't as fast as main memory we do not try to hook it into main * memeory as that would simply reduce performance on the system. Using * it as a block device allows us to use it as high speed swap or for a - * high speed disk device of some sort. Which becomes very usefull on - * diskless systems in the embeded market I might add. + * high speed disk device of some sort. Which becomes very useful on + * diskless systems in the embedded market I might add. * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I have diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.4.3/linux/drivers/net/3c505.c Tue Mar 20 12:05:00 2001 +++ linux/drivers/net/3c505.c Thu Apr 12 12:15:25 2001 @@ -149,7 +149,7 @@ #ifdef ELP_DEBUG static const int elp_debug = ELP_DEBUG; #else -static const int elp_debug = 0; +static const int elp_debug; #endif /* diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.4.3/linux/drivers/net/3c507.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/3c507.c Thu Apr 12 12:15:25 2001 @@ -323,7 +323,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) { - static unsigned char init_ID_done = 0, version_printed = 0; + static unsigned char init_ID_done, version_printed; int i, irq, irqval, retval; struct net_local *lp; @@ -858,7 +858,7 @@ #ifdef MODULE static struct net_device dev_3c507; static int io = 0x300; -static int irq = 0; +static int irq; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.4.3/linux/drivers/net/3c509.c Sun Mar 25 18:14:25 2001 +++ linux/drivers/net/3c509.c Thu Apr 12 12:15:25 2001 @@ -144,7 +144,7 @@ char mca_slot; }; static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/ -static struct net_device *el3_root_dev = NULL; +static struct net_device *el3_root_dev; static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); @@ -209,10 +209,10 @@ short lrs_state = 0xff, i; int ioaddr, irq, if_port; u16 phys_addr[3]; - static int current_tag = 0; + static int current_tag; int mca_slot = -1; #ifdef CONFIG_ISAPNP - static int pnp_cards = 0; + static int pnp_cards; #endif /* CONFIG_ISAPNP */ if (dev) SET_MODULE_OWNER(dev); @@ -942,7 +942,7 @@ int ioaddr = dev->base_addr; if (el3_debug > 1) { - static int old = 0; + static int old; if (old != dev->mc_count) { old = dev->mc_count; printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.4.3/linux/drivers/net/3c515.c Tue Mar 20 12:05:00 2001 +++ linux/drivers/net/3c515.c Thu Apr 12 12:15:25 2001 @@ -407,7 +407,7 @@ #ifdef MODULE static int debug = -1; /* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_corkscrew_dev = NULL; +static struct net_device *root_corkscrew_dev; int init_module(void) { @@ -445,7 +445,7 @@ static int ioaddr; #ifdef CONFIG_ISAPNP short i; - static int pnp_cards = 0; + static int pnp_cards; #endif #ifdef CONFIG_ISAPNP @@ -1166,7 +1166,7 @@ printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name, status, latency); if ((status & 0xE000) != 0xE000) { - static int donedidthis = 0; + static int donedidthis; /* Some interrupt controllers store a bogus interrupt from boot-time. Ignore a single early interrupt, but don't hang the machine for other interrupt problems. */ @@ -1234,7 +1234,7 @@ outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat = 0; + static int DoneDidThat; if (corkscrew_debug > 4) printk("%s: Updating stats.\n", dev->name); diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.4.3/linux/drivers/net/3c523.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/3c523.c Thu Apr 12 12:15:25 2001 @@ -404,7 +404,7 @@ int __init elmc_probe(struct net_device *dev) { - static int slot = 0; + static int slot; int base_addr = dev->base_addr; int irq = dev->irq; u_char status = 0; diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.4.3/linux/drivers/net/3c527.c Sun Mar 4 14:05:04 2001 +++ linux/drivers/net/3c527.c Thu Apr 12 12:15:25 2001 @@ -270,7 +270,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) { - static unsigned version_printed = 0; + static unsigned version_printed; int i, err; u8 POS; u32 base; diff -u --recursive --new-file v2.4.3/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.4.3/linux/drivers/net/3c59x.c Tue Mar 6 19:28:33 2001 +++ linux/drivers/net/3c59x.c Thu Apr 12 12:16:35 2001 @@ -192,6 +192,7 @@ #error You must compile this driver with "-O". #endif +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> diff -u --recursive --new-file v2.4.3/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.3/linux/drivers/net/8139too.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/8139too.c Fri Apr 6 11:50:02 2001 @@ -149,7 +149,7 @@ #include <asm/io.h> -#define RTL8139_VERSION "0.9.15c" +#define RTL8139_VERSION "0.9.15d" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -204,6 +204,7 @@ #define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) +#define RX_EARLY_THRESH 2 /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -662,7 +663,7 @@ TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap | + (RX_EARLY_THRESH << RxCfgEarlyRxShift) | RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); @@ -1843,10 +1844,9 @@ } -/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the - field alignments and semantics. */ static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr) + struct rtl8139_private *tp, void *ioaddr, + u16 status) { unsigned char *rx_ring; u16 cur_rx; @@ -1863,6 +1863,11 @@ RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); + if (status & RxFIFOOver) + status = RxOverflow | RxOK; + else + status = RxOK; + while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; @@ -1889,17 +1894,10 @@ } #endif - /* E. Gill */ - /* Note from BSD driver: - * Here's a totally undocumented fact for you. When the - * RealTek chip is in the process of copying a packet into - * RAM for you, the length will be 0xfff0. If you spot a - * packet header with this value, you need to stop. The - * datasheet makes absolutely no mention of this and - * RealTek should be shot for this. - */ - if (rx_size == 0xfff0) + if (rx_size == 0xfff0) { /* Early Rx in progress */ + RTL_W16_F (IntrStatus, status); break; + } /* If Rx err or invalid rx_size/rx_status received * (which happens if we get lost in the ring), @@ -1942,7 +1940,9 @@ } cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - RTL_W16_F (RxBufPtr, cur_rx - 16); + RTL_W16 (RxBufPtr, cur_rx - 16); + RTL_W16_F (IntrStatus, status); + barrier(); } DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," @@ -1996,11 +1996,6 @@ tp->stats.rx_length_errors++; if (status & (RxUnderrun | RxFIFOOver)) tp->stats.rx_fifo_errors++; - if (status & RxOverflow) { - tp->stats.rx_over_errors++; - tp->cur_rx = RTL_R16 (RxBufAddr) % RX_BUF_LEN; - RTL_W16_F (RxBufPtr, tp->cur_rx - 16); - } if (status & PCIErr) { u16 pci_cmd_status; pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); @@ -2020,7 +2015,8 @@ struct rtl8139_private *tp = dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ + int ackstat, status; + int link_changed = 0; /* avoid bogus "uninit" warning */ do { status = RTL_R16 (IntrStatus); @@ -2053,26 +2049,26 @@ CPU speed, lower CPU speed --> more errors). After clearing the RxOverflow bit the transfer of the packet was repeated and all data are error free transferred */ - RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); + ackstat = status & ~(RxFIFOOver | RxOverflow | RxOK); + RTL_W16 (IntrStatus, ackstat); - DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, - RTL_R16 (IntrStatus)); + DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", + dev->name, ackstat, status, RTL_R16 (IntrStatus)); if ((status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) break; + if (netif_running (dev) && + status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ + rtl8139_rx_interrupt (dev, tp, ioaddr, status); + /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | RxErr)) rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - - if (netif_running (dev) && - status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ - rtl8139_rx_interrupt (dev, tp, ioaddr); if (netif_running (dev) && status & (TxOK | TxErr)) { diff -u --recursive --new-file v2.4.3/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.4.3/linux/drivers/net/82596.c Tue Mar 6 19:28:33 2001 +++ linux/drivers/net/82596.c Thu Apr 12 12:15:25 2001 @@ -1095,7 +1095,7 @@ int i; struct i596_private *lp; char eth_addr[8]; - static int probed = 0; + static int probed; if (probed) return -ENODEV; diff -u --recursive --new-file v2.4.3/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.4.3/linux/drivers/net/a2065.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/a2065.c Thu Apr 12 12:15:25 2001 @@ -137,7 +137,7 @@ }; #ifdef MODULE -static struct lance_private *root_a2065_dev = NULL; +static struct lance_private *root_a2065_dev; #endif #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ diff -u --recursive --new-file v2.4.3/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.4.3/linux/drivers/net/acenic.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/acenic.c Fri Apr 13 20:26:07 2001 @@ -2,7 +2,7 @@ * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * - * Copyright 1998-2000 by Jes Sorensen, <jes@linuxcare.com>. + * Copyright 1998-2001 by Jes Sorensen, <jes@linuxcare.com>. * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. @@ -62,6 +62,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/mm.h> +#include <linux/highmem.h> #include <linux/sockios.h> #ifdef SIOCETHTOOL @@ -282,6 +283,10 @@ #include "acenic_firmware.h" +#ifndef tigon2FwReleaseLocal +#define tigon2FwReleaseLocal 0 +#endif + /* * This driver currently supports Tigon I and Tigon II based cards * including the Alteon AceNIC, the 3Com 3C985[B] and NetGear @@ -464,7 +469,7 @@ * Jumbo frames are enabled, the user wants optimal tuning for that case. */ #define DEF_TX_COAL 400 /* 996 */ -#define DEF_TX_MAX_DESC 40 +#define DEF_TX_MAX_DESC 60 /* was 40 */ #define DEF_RX_COAL 120 /* 1000 */ #define DEF_RX_MAX_DESC 25 #define DEF_TX_RATIO 21 /* 24 */ @@ -475,10 +480,26 @@ #define DEF_JUMBO_RX_MAX_DESC 6 #define DEF_JUMBO_TX_RATIO 21 -#define TX_COAL_INTS_ONLY 0 /* seems not worth it */ +#if tigon2FwReleaseLocal < 20001118 +/* + * Standard firmware and early modifications duplicate + * IRQ load without this flag (coal timer is never reset). + * Note that with this flag tx_coal should be less than + * time to xmit full tx ring. + * 400usec is not so bad for tx ring size of 128. + */ +#define TX_COAL_INTS_ONLY 1 /* worth it */ +#else +/* + * With modified firmware, this is not necessary, but still useful. + */ +#define TX_COAL_INTS_ONLY 1 +#endif + #define DEF_TRACE 0 #define DEF_STAT (2 * TICKS_PER_SEC) + static int link[ACE_MAX_MOD_PARMS]; static int trace[ACE_MAX_MOD_PARMS]; static int tx_coal_tick[ACE_MAX_MOD_PARMS]; @@ -489,7 +510,7 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static char version[] __initdata = - "acenic.c: v0.50 02/02/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n" + "acenic.c: v0.80 03/08/2001 Jes Sorensen, linux-acenic@SunSITE.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev; @@ -560,6 +581,12 @@ dev->irq = pdev->irq; dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + if (1) { + static void ace_watchdog(struct net_device *dev); + dev->tx_timeout = &ace_watchdog; + dev->watchdog_timeo = 5*HZ; + } dev->stop = &ace_close; dev->get_stats = &ace_get_stats; dev->set_multicast_list = &ace_set_multicast_list; @@ -762,15 +789,17 @@ struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; if (skb) { +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_std_skbuff[i].mapping; - - ap->rx_std_ring[i].size = 0; - ap->skb->rx_std_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); +#endif + + ap->rx_std_ring[i].size = 0; + ap->skb->rx_std_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } @@ -779,14 +808,16 @@ struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; if (skb) { +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_mini_skbuff[i].mapping; - ap->rx_mini_ring[i].size = 0; - ap->skb->rx_mini_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); +#endif + ap->rx_mini_ring[i].size = 0; + ap->skb->rx_mini_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } @@ -794,15 +825,17 @@ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; if (skb) { +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; mapping = ap->skb->rx_jumbo_skbuff[i].mapping; - - ap->rx_jumbo_ring[i].size = 0; - ap->skb->rx_jumbo_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, ACE_JUMBO_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); +#endif + + ap->rx_jumbo_ring[i].size = 0; + ap->skb->rx_jumbo_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } @@ -1177,10 +1210,21 @@ printk(KERN_INFO " Disabling PCI memory " "write and invalidate\n"); } +#ifdef __alpha__ + /* This maximizes throughput on my alpha. */ + tmp |= DMA_WRITE_MAX_128; +#endif } else if (ap->pci_command & PCI_COMMAND_INVALIDATE) { printk(KERN_INFO " PCI memory write & invalidate " "enabled by BIOS, enabling counter measures\n"); +#ifdef __alpha__ + /* All the docs sy MUST NOT. Well, I did. + * Nothing terrible happens, if we load wrong size. + * Bit w&i still works better! + */ + tmp |= DMA_WRITE_MAX_128; +#else switch(SMP_CACHE_BYTES) { case 16: tmp |= DMA_WRITE_MAX_16; @@ -1199,6 +1243,7 @@ pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); } +#endif } } @@ -1218,6 +1263,9 @@ tmp |= DMA_READ_MAX_64; tmp |= DMA_WRITE_MAX_64; #endif +#ifdef __alpha__ + tmp |= DMA_READ_MAX_128; +#endif writel(tmp, ®s->PciState); #if 0 @@ -1313,7 +1361,7 @@ set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma); info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; - info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); @@ -1328,7 +1376,7 @@ (ap->rx_ring_base_dma + (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES))); info->rx_jumbo_ctrl.max_len = 0; - info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); @@ -1349,7 +1397,7 @@ (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES)))); info->rx_mini_ctrl.max_len = ACE_MINI_SIZE; - info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR; for (i = 0; i < RX_MINI_RING_ENTRIES; i++) ap->rx_mini_ring[i].flags = @@ -1384,13 +1432,10 @@ set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma); info->tx_ctrl.max_len = TX_RING_ENTRIES; - - tmp = 0; + tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING; #if TX_COAL_INTS_ONLY tmp |= RCB_FLG_COAL_INT_ONLY; #endif - tmp |= RCB_FLG_TX_HOST_RING; - info->tx_ctrl.flags = tmp; set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma); @@ -1398,8 +1443,13 @@ /* * Potential item for tuning parameter */ +#if 0 /* NO */ + writel(DMA_THRESH_16W, ®s->DmaReadCfg); + writel(DMA_THRESH_16W, ®s->DmaWriteCfg); +#else writel(DMA_THRESH_8W, ®s->DmaReadCfg); writel(DMA_THRESH_8W, ®s->DmaWriteCfg); +#endif writel(0, ®s->MaskInt); writel(1, ®s->IfIdx); @@ -1430,7 +1480,7 @@ if (trace[board_idx]) writel(trace[board_idx], ®s->TuneTrace); - if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64)) + if ((tx_ratio[board_idx] > 0) && (tx_ratio[board_idx] < 64)) writel(tx_ratio[board_idx], ®s->TxBufRat); } @@ -1501,7 +1551,6 @@ * tx ints before we are up and running, which may cause a null * pointer access in the int handler. */ - ap->tx_full = 0; ap->cur_rx = 0; ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0; @@ -1510,6 +1559,11 @@ writel(0, ®s->RxRetCsm); /* + * Zero the stats before starting the interface + */ + memset(&ap->stats, 0, sizeof(ap->stats)); + + /* * Start the NIC CPU */ writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); @@ -1611,12 +1665,9 @@ } -/* - * Monitor the card to detect hangs. - */ -static void ace_timer(unsigned long data) +static void ace_watchdog(struct net_device *data) { - struct net_device *dev = (struct net_device *)data; + struct net_device *dev = data; struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; @@ -1628,13 +1679,13 @@ if (*ap->tx_csm != ap->tx_ret_csm) { printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n", dev->name, (unsigned int)readl(®s->HostCtrl)); + /* This can happen due to ieee flow control. */ + } else { + printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n", dev->name); + netif_wake_queue(dev); } - - ap->timer.expires = jiffies + (5/2*HZ); - add_timer(&ap->timer); } - static void ace_tasklet(unsigned long dev) { struct ace_private *ap = ((struct net_device *)dev)->priv; @@ -1719,7 +1770,9 @@ ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; +#ifndef DUMMY_PCI_UNMAP ap->skb->rx_std_skbuff[idx].mapping = mapping; +#endif rd = &ap->rx_std_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1781,7 +1834,9 @@ ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_mini_skbuff[idx].skb = skb; +#ifndef DUMMY_PCI_UNMAP ap->skb->rx_mini_skbuff[idx].mapping = mapping; +#endif rd = &ap->rx_mini_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1840,7 +1895,9 @@ ACE_JUMBO_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_jumbo_skbuff[idx].skb = skb; +#ifndef DUMMY_PCI_UNMAP ap->skb->rx_jumbo_skbuff[idx].mapping = mapping; +#endif rd = &ap->rx_jumbo_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1870,8 +1927,9 @@ clear_bit(0, &ap->jumbo_refill_busy); return; error_out: - printk(KERN_INFO "Out of memory when allocating " - "jumbo receive buffers\n"); + if (net_ratelimit()) + printk(KERN_INFO "Out of memory when allocating " + "jumbo receive buffers\n"); goto out; } @@ -1902,9 +1960,16 @@ u16 code = ap->evt_ring[evtcsm].code; switch (code) { case E_C_LINK_UP: - printk(KERN_WARNING "%s: Optical link UP\n", - dev->name); + { + u32 state = readl(&ap->regs->GigLnkState); + printk(KERN_WARNING "%s: Optical link UP " + "(%s Duplex, Flow Control: %s%s)\n", + dev->name, + state & LNK_FULL_DUPLEX ? "Full":"Half", + state & LNK_TX_FLOW_CTL_Y ? "TX " : "", + state & LNK_RX_FLOW_CTL_Y ? "RX" : ""); break; + } case E_C_LINK_DOWN: printk(KERN_WARNING "%s: Optical link DOWN\n", dev->name); @@ -1965,8 +2030,6 @@ ap->rx_jumbo_skbprd = 0; printk(KERN_INFO "%s: Jumbo ring flushed\n", dev->name); - if (!ap->tx_full) - netif_wake_queue(dev); clear_bit(0, &ap->jumbo_refill_busy); break; } @@ -1994,12 +2057,13 @@ struct sk_buff *skb; struct rx_desc *rxdesc, *retdesc; u32 skbidx; - int desc_type, mapsize; + int bd_flags, desc_type, mapsize; u16 csum; retdesc = &ap->rx_return_ring[idx]; skbidx = retdesc->idx; - desc_type = retdesc->flags & (BD_FLG_JUMBO | BD_FLG_MINI); + bd_flags = retdesc->flags; + desc_type = bd_flags & (BD_FLG_JUMBO | BD_FLG_MINI); switch(desc_type) { /* @@ -2036,8 +2100,10 @@ skb = rip->skb; rip->skb = NULL; +#ifndef DUMMY_PCI_UNMAP pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE); +#endif skb_put(skb, retdesc->size); #if 0 /* unncessary */ @@ -2053,15 +2119,15 @@ skb->protocol = eth_type_trans(skb, dev); /* - * If the checksum is correct and this is not a - * fragment, tell the stack that the data is correct. + * Instead of forcing the poor tigon mips cpu to calculate + * pseudo hdr checksum, we do this ourselves. */ - if(!(csum ^ 0xffff) && - (!(((struct iphdr *)skb->data)->frag_off & - __constant_htons(IP_MF|IP_OFFSET)))) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else + if (bd_flags & BD_FLG_TCP_UDP_SUM) { + skb->csum = htons(csum); + skb->ip_summed = CHECKSUM_HW; + } else { skb->ip_summed = CHECKSUM_NONE; + } netif_rx(skb); /* send it up */ @@ -2094,6 +2160,75 @@ } +static inline void ace_tx_int(struct net_device *dev, + u32 txcsm, u32 idx) +{ + struct ace_private *ap = dev->priv; + + do { + struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP + dma_addr_t mapping; +#endif + struct tx_ring_info *info; + + info = ap->skb->tx_skbuff + idx; + skb = info->skb; +#ifndef DUMMY_PCI_UNMAP + mapping = info->mapping; + + if (mapping) { + pci_unmap_single(ap->pdev, mapping, info->maplen, + PCI_DMA_TODEVICE); + info->mapping = 0; + } +#endif + if (skb) { + ap->stats.tx_packets++; + ap->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + info->skb = NULL; + } + + idx = (idx + 1) % TX_RING_ENTRIES; + } while (idx != txcsm); + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + + wmb(); + ap->tx_ret_csm = txcsm; + + /* So... tx_ret_csm is advanced _after_ check for device wakeup. + * + * We could try to make it before. In this case we would get + * the following race condition: hard_start_xmit on other cpu + * enters after we advanced tx_ret_csm and fills space, + * which we have just freed, so that we make illegal device wakeup. + * There is no good way to workaround this (at entry + * to ace_start_xmit detects this condition and prevents + * ring corruption, but it is not a good workaround.) + * + * When tx_ret_csm is advanced after, we wake up device _only_ + * if we really have some space in ring (though the core doing + * hard_start_xmit can see full ring for some period and has to + * synchronize.) Superb. + * BUT! We get another subtle race condition. hard_start_xmit + * may think that ring is full between wakeup and advancing + * tx_ret_csm and will stop device instantly! It is not so bad. + * We are guaranteed that there is something in ring, so that + * the next irq will resume transmission. To speedup this we could + * mark descriptor, which closes ring with BD_FLG_COAL_NOW + * (see ace_start_xmit). + * + * Well, this dilemma exists in all lock-free devices. + * We, following scheme used in drivers by Donald Becker, + * select the least dangerous. + * --ANK + */ +} + + static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) { struct ace_private *ap; @@ -2115,9 +2250,14 @@ return; /* - * Tell the card not to generate interrupts while we are in here. + * ACK intr now. Otherwise we will lose updates to rx_ret_prd, + * which happened _after_ rxretprd = *ap->rx_ret_prd; but before + * writel(0, ®s->Mb0Lo). + * + * "IRQ avoidance" recommended in docs applies to IRQs served + * threads and it is wrong even for that case. */ - writel(1, ®s->Mb0Lo); + writel(0, ®s->Mb0Lo); /* * There is no conflict between transmit handling in @@ -2136,75 +2276,15 @@ idx = ap->tx_ret_csm; if (txcsm != idx) { - do { - struct sk_buff *skb; - - skb = ap->skb->tx_skbuff[idx].skb; - /* - * Race condition between the code cleaning - * the tx queue in the interrupt handler and the - * interface close, - * - * This is a kludge that really should be fixed - * by preventing the driver from generating a tx - * interrupt when the packet has already been - * removed from the tx queue. - * - * Nailed by Don Dugger and Chip Salzenberg of - * VA Linux. - */ - if (skb) { - dma_addr_t mapping; - - mapping = ap->skb->tx_skbuff[idx].mapping; - - ap->stats.tx_packets++; - ap->stats.tx_bytes += skb->len; - pci_unmap_single(ap->pdev, mapping, skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - - ap->skb->tx_skbuff[idx].skb = NULL; - } - - /* - * Question here is whether one should not skip - * these writes - I have never seen any errors - * caused by the NIC actually trying to access - * these incorrectly. - */ -#ifdef ACE_64BIT_PTR - ap->tx_ring[idx].addr.addrhi = 0; -#endif - ap->tx_ring[idx].addr.addrlo = 0; - ap->tx_ring[idx].flagsize = 0; - - idx = (idx + 1) % TX_RING_ENTRIES; - } while (idx != txcsm); - /* - * Once we actually get to this point the tx ring has - * already been trimmed thus it cannot be full! - * Ie. skip the comparison of the tx producer vs. the - * consumer. + * If each skb takes only one descriptor this check degenerates + * to identity, because new space has just been opened. + * But if skbs are fragmented we must check that this index + * update releases enough of space, otherwise we just + * wait for device to make more work. */ - if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) { - /* - * This does not need to be atomic (and expensive), - * I've seen cases where it would fail otherwise ;-( - */ - netif_wake_queue(dev); - ace_mark_net_bh(); - - /* - * TX ring is no longer full, aka the - * transmitter is working fine - kill timer. - */ - del_timer(&ap->timer); - } - - ap->tx_ret_csm = txcsm; - wmb(); + if (!tx_ring_full(txcsm, ap->tx_prd)) + ace_tx_int(dev, txcsm, idx); } evtcsm = readl(®s->EvtCsm); @@ -2272,11 +2352,6 @@ tasklet_schedule(&ap->ace_tasklet); } } - - /* - * Allow the card to generate interrupts again - */ - writel(0, ®s->Mb0Lo); } @@ -2296,11 +2371,6 @@ writel(dev->mtu + ETH_HLEN + 4, ®s->IfMtu); - /* - * Zero the stats when restarting the interface... - */ - memset(&ap->stats, 0, sizeof(ap->stats)); - cmd.evt = C_CLEAR_STATS; cmd.code = 0; cmd.idx = 0; @@ -2338,13 +2408,6 @@ ACE_MOD_INC_USE_COUNT; /* - * Setup the timer - */ - init_timer(&ap->timer); - ap->timer.data = (unsigned long)dev; - ap->timer.function = ace_timer; - - /* * Setup the bottom half rx ring refill handler */ tasklet_init(&ap->ace_tasklet, ace_tasklet, (unsigned long)dev); @@ -2361,13 +2424,17 @@ short i; ace_if_down(dev); + + /* + * Without (or before) releasing irq and stopping hardware, this + * is an absolute non-sense, by the way. It will be reset instantly + * by the first irq. + */ netif_stop_queue(dev); ap = dev->priv; regs = ap->regs; - del_timer(&ap->timer); - if (ap->promisc) { cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_DISABLE; @@ -2392,16 +2459,26 @@ for (i = 0; i < TX_RING_ENTRIES; i++) { struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; +#endif + struct tx_ring_info *info; - skb = ap->skb->tx_skbuff[i].skb; - mapping = ap->skb->tx_skbuff[i].mapping; - if (skb) { - memset(&ap->tx_ring[i].addr, 0, sizeof(struct tx_desc)); - pci_unmap_single(ap->pdev, mapping, skb->len, + info = ap->skb->tx_skbuff + i; + skb = info->skb; +#ifndef DUMMY_PCI_UNMAP + mapping = info->mapping; + + if (mapping) { + memset(ap->tx_ring+i, 0, sizeof(struct tx_desc)); + pci_unmap_single(ap->pdev, mapping, info->maplen, PCI_DMA_TODEVICE); + info->mapping = 0; + } +#endif + if (skb) { dev_kfree_skb(skb); - ap->skb->tx_skbuff[i].skb = NULL; + info->skb = NULL; } } @@ -2419,85 +2496,216 @@ } +/* + * Following below should be (in more clean form!) in arch/ARCH/kernel/pci_*. + * For now, let it stay here. + */ +#if defined(CONFIG_HIGHMEM) && MAX_SKB_FRAGS +#ifndef DUMMY_PCI_UNMAP +#error Sorry, cannot DMA from high memory on this architecture. +#endif + +#if defined(CONFIG_X86) +#define DMAADDR_OFFSET 0 +typedef unsigned long long dmaaddr_high_t; +#elif defined(CONFIG_PPC) +#define DMAADDR_OFFSET PCI_DRAM_OFFSET +typedef unsigned long dmaaddr_high_t; +#endif + + +static inline dmaaddr_high_t +pci_map_single_high(struct pci_dev *hwdev, struct page *page, + int offset, size_t size, int dir) +{ + dmaaddr_high_t phys; + + phys = (page-mem_map) * (dmaaddr_high_t) PAGE_SIZE + offset; + + return (phys + DMAADDR_OFFSET); +} + +#else + +typedef unsigned long dmaaddr_high_t; + +static inline dmaaddr_high_t +pci_map_single_high(struct pci_dev *hwdev, struct page *page, + int offset, size_t size, int dir) +{ + return pci_map_single(hwdev, page_address(page) + offset, size, dir); +} + +#endif + + +static inline dmaaddr_high_t +ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb, + struct sk_buff *tail, u32 idx) +{ + unsigned long addr; + struct tx_ring_info *info; + + addr = pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + + info = ap->skb->tx_skbuff + idx; + info->skb = tail; +#ifndef DUMMY_PCI_UNMAP + info->mapping = addr; + info->maplen = skb->len; +#endif + return addr; +} + + +static inline void +ace_load_tx_bd(struct tx_desc *desc, dmaaddr_high_t addr, u32 flagsize) +{ +#if !USE_TX_COAL_NOW + flagsize &= ~BD_FLG_COAL_NOW; +#endif + +#ifdef ACE_64BIT_PTR + desc->addr.addrhi = addr >> 32; +#endif + desc->addr.addrlo = addr; + desc->flagsize = flagsize; +} + + static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; - unsigned long addr; + struct tx_desc *desc; u32 idx, flagsize; - /* + /* * This only happens with pre-softnet, ie. 2.2.x kernels. - */ + */ if (early_stop_netif_stop_queue(dev)) - return 1; + return 1; + +restart: idx = ap->tx_prd; - if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) { - ap->tx_full = 1; -#if DEBUG - printk("%s: trying to transmit while the tx ring is full " - "- this should not happen!\n", dev->name); + if (tx_ring_full(ap->tx_ret_csm, idx)) + goto overflow; + +#if MAX_SKB_FRAGS + if (!skb_shinfo(skb)->nr_frags) #endif - return 1; - } + { + unsigned long addr; - ap->skb->tx_skbuff[idx].skb = skb; - ap->skb->tx_skbuff[idx].mapping = - pci_map_single(ap->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping; - flagsize = (skb->len << 16) | (BD_FLG_END) ; - set_aceaddr(&ap->tx_ring[idx].addr, addr); - ap->tx_ring[idx].flagsize = flagsize; - wmb(); - idx = (idx + 1) % TX_RING_ENTRIES; + addr = ace_map_tx_skb(ap, skb, skb, idx); + flagsize = (skb->len << 16) | (BD_FLG_END); + if (skb->ip_summed == CHECKSUM_HW) + flagsize |= BD_FLG_TCP_UDP_SUM; + desc = ap->tx_ring + idx; + idx = (idx + 1) % TX_RING_ENTRIES; + + /* Look at ace_tx_int for explanations. */ + if (tx_ring_full(ap->tx_ret_csm, idx)) + flagsize |= BD_FLG_COAL_NOW; + + ace_load_tx_bd(desc, addr, flagsize); + } +#if MAX_SKB_FRAGS + else { + unsigned long addr; + int i, len = 0; + + addr = ace_map_tx_skb(ap, skb, NULL, idx); + flagsize = ((skb->len - skb->data_len) << 16); + if (skb->ip_summed == CHECKSUM_HW) + flagsize |= BD_FLG_TCP_UDP_SUM; + + ace_load_tx_bd(ap->tx_ring + idx, addr, flagsize); + + idx = (idx + 1) % TX_RING_ENTRIES; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct tx_ring_info *info; + dmaaddr_high_t phys; + + len += frag->size; + info = ap->skb->tx_skbuff + idx; + desc = ap->tx_ring + idx; + + phys = pci_map_single_high(ap->pdev, frag->page, + frag->page_offset, + frag->size, + PCI_DMA_TODEVICE); + + flagsize = (frag->size << 16); + if (skb->ip_summed == CHECKSUM_HW) + flagsize |= BD_FLG_TCP_UDP_SUM; + idx = (idx + 1) % TX_RING_ENTRIES; - ap->tx_prd = idx; - ace_set_txprd(regs, ap, idx); + if (i == skb_shinfo(skb)->nr_frags-1) { + flagsize |= BD_FLG_END; + if (tx_ring_full(ap->tx_ret_csm, idx)) + flagsize |= BD_FLG_COAL_NOW; + + /* + * Only the last fragment frees + * the skb! + */ + info->skb = skb; + } else { + info->skb = NULL; + } +#ifndef DUMMY_PCI_UNMAP + info->mapping = phys; + info->maplen = frag->size; +#endif + ace_load_tx_bd(desc, phys, flagsize); + } + } +#endif - /* - * tx_csm is set by the NIC whereas we set tx_ret_csm which - * is always trying to catch tx_csm - */ - if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm) { - ap->tx_full = 1; - /* - * Queue is full, add timer to detect whether the - * transmitter is stuck. Use mod_timer as we can get - * into the situation where we risk adding several - * timers. - */ - mod_timer(&ap->timer, jiffies + (3 * HZ)); + wmb(); + ap->tx_prd = idx; + ace_set_txprd(regs, ap, idx); + + if (flagsize & BD_FLG_COAL_NOW) { + netif_stop_queue(dev); /* - * The following check will fix a race between the interrupt - * handler increasing the tx_ret_csm and testing for tx_full - * and this tx routine's testing the tx_ret_csm and setting - * the tx_full; note that this fix makes assumptions on the - * ordering of writes (sequential consistency will fly; TSO - * processor order would work too) but that's what lock-less - * programming is all about + * A TX-descriptor producer (an IRQ) might have gotten + * inbetween, making the ring free again. Since xmit is + * serialized, this is the only situation we have to + * re-test. */ - if (((idx + 2) % TX_RING_ENTRIES != ap->tx_ret_csm) - && xchg(&ap->tx_full, 0)) { - del_timer(&ap->timer); - /* - * We may not need this one in the post softnet era - * in this case this can be changed to a - * early_stop_netif_wake_queue(dev); - */ + if (!tx_ring_full(ap->tx_ret_csm, idx)) netif_wake_queue(dev); - } else { - late_stop_netif_stop_queue(dev); - } - } else { - early_stop_netif_wake_queue(dev); } dev->trans_start = jiffies; return 0; + +overflow: + /* + * This race condition is unavoidable with lock-free drivers. + * We wake up the queue _before_ tx_prd is advanced, so that we can + * enter hard_start_xmit too early, while tx ring still looks closed. + * This happens ~1-4 times per 100000 packets, so that we can allow + * to loop syncing to other CPU. Probably, we need an additional + * wmb() in ace_tx_intr as well. + * + * Note that this race is relieved by reserving one more entry + * in tx ring than it is necessary (see original non-SG driver). + * However, with SG we need to reserve 2*MAX_SKB_FRAGS+1, which + * is already overkill. + * + * Alternative is to return with 1 not throttling queue. In this + * case loop becomes longer, no more useful effects. + */ + barrier(); + goto restart; } @@ -2522,7 +2730,6 @@ ace_set_rxtx_parms(dev, 1); } } else { - netif_stop_queue(dev); while (test_and_set_bit(0, &ap->jumbo_refill_busy)); synchronize_irq(); ace_set_rxtx_parms(dev, 0); @@ -2542,27 +2749,12 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { -#ifdef SIOCETHTOOL struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; +#ifdef SIOCETHTOOL struct ethtool_cmd ecmd; u32 link, speed; -#ifdef SPIN_DEBUG - if (cmd == (SIOCDEVPRIVATE+0x0e)) { - printk(KERN_NOTICE "%s: dumping debug info\n", dev->name); - printk(KERN_NOTICE "%s: tbusy %li, tx_ret_csm %i, " - "tx_prd %i\n", dev->name, dev->tbusy, - ap->tx_ret_csm, ap->tx_prd); - printk(KERN_NOTICE "%s: cur_rx %i, std_refill %li, " - "mini_rx %i, mini_refill %li\n", dev->name, - atomic_read(&ap->cur_rx_bufs), ap->std_refill_busy, - atomic_read(&ap->cur_mini_bufs), ap->mini_refill_busy); - printk(KERN_NOTICE "%s: CpuCtrl %08x\n", - dev->name, readl(®s->CpuCtrl)); - return 0; - } -#endif if (cmd != SIOCETHTOOL) return -EOPNOTSUPP; if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd))) @@ -2699,7 +2891,8 @@ regs = ((struct ace_private *)dev->priv)->regs; writel(da[0] << 8 | da[1], ®s->MacAddrHi); - writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5] , ®s->MacAddrLo); + writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5], + ®s->MacAddrLo); cmd.evt = C_SET_MAC_ADDR; cmd.code = 0; @@ -2774,11 +2967,12 @@ ap->stats.multicast = readl(&mac_stats->kept_mc); ap->stats.collisions = readl(&mac_stats->coll); - return(&ap->stats); + return &ap->stats; } -static void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size) +static void __init ace_copy(struct ace_regs *regs, void *src, + u32 dest, int size) { unsigned long tdest; u32 *wsrc; diff -u --recursive --new-file v2.4.3/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.4.3/linux/drivers/net/acenic.h Sat Dec 30 11:23:13 2000 +++ linux/drivers/net/acenic.h Thu Apr 12 12:11:39 2001 @@ -1,6 +1,19 @@ #ifndef _ACENIC_H_ #define _ACENIC_H_ + +/* + * Generate TX index update each time, when TX ring is closed. + * Normally, this is not useful, because results in more dma (and irqs + * without TX_COAL_INTS_ONLY). + */ +#define USE_TX_COAL_NOW 0 + +#ifndef MAX_SKB_FRAGS +#define MAX_SKB_FRAGS 0 +#endif + + /* * Addressing: * @@ -258,7 +271,12 @@ * DMA config */ +#define DMA_THRESH_1W 0x10 +#define DMA_THRESH_2W 0x20 +#define DMA_THRESH_4W 0x40 #define DMA_THRESH_8W 0x80 +#define DMA_THRESH_16W 0x100 +#define DMA_THRESH_32W 0x0 /* not described in doc, but exists. */ /* @@ -399,6 +417,7 @@ #define BD_FLG_IP_SUM 0x02 #define BD_FLG_END 0x04 #define BD_FLG_JUMBO 0x10 +#define BD_FLG_COAL_NOW 0x800 #define BD_FLG_MINI 0x1000 @@ -407,6 +426,7 @@ */ #define RCB_FLG_TCP_UDP_SUM 0x01 #define RCB_FLG_IP_SUM 0x02 +#define RCB_FLG_NO_PSEUDO_HDR 0x08 #define RCB_FLG_VLAN_ASSIST 0x10 #define RCB_FLG_COAL_INT_ONLY 0x20 #define RCB_FLG_TX_HOST_RING 0x40 @@ -561,12 +581,29 @@ aceaddr stats2_ptr; }; +#if defined(CONFIG_X86) || defined(CONFIG_PPC) +/* Intel has null pci_unmap_single, no reasons to remember mapping. */ +#define DUMMY_PCI_UNMAP +#endif struct ring_info { struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP dma_addr_t mapping; +#endif }; +/* Funny... As soon as we add maplen on alpha, it starts to work + * much slower. Hmm... is it because struct does not fit to one cacheline? + * So, split tx_ring_info. + */ +struct tx_ring_info { + struct sk_buff *skb; +#ifndef DUMMY_PCI_UNMAP + dma_addr_t mapping; + int maplen; +#endif +}; /* * struct ace_skb holding the rings of skb's. This is an awful lot of @@ -575,7 +612,7 @@ */ struct ace_skb { - struct ring_info tx_skbuff[TX_RING_ENTRIES]; + struct tx_ring_info tx_skbuff[TX_RING_ENTRIES]; struct ring_info rx_std_skbuff[RX_STD_RING_ENTRIES]; struct ring_info rx_mini_skbuff[RX_MINI_RING_ENTRIES]; struct ring_info rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES]; @@ -605,11 +642,10 @@ /* * TX elements */ - struct tx_desc *tx_ring - __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct timer_list timer; /* used by TX handling only */ + struct tx_desc *tx_ring; u32 tx_prd; - volatile u32 tx_full, tx_ret_csm; + volatile u32 tx_ret_csm; + struct timer_list timer; /* * RX elements @@ -657,6 +693,22 @@ }; +#define TX_RESERVED MAX_SKB_FRAGS + +static inline int tx_space (u32 csm, u32 prd) +{ + return (csm - prd - 1) & (TX_RING_ENTRIES - 1); +} + +#define tx_free(ap) tx_space((ap)->tx_ret_csm, (ap)->tx_prd) + +#if MAX_SKB_FRAGS +#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED) +#else +#define tx_ring_full 0 +#endif + + static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr) { unsigned long baddr = (unsigned long) addr; @@ -717,14 +769,10 @@ static int ace_open(struct net_device *dev); static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev); static int ace_close(struct net_device *dev); -static void ace_timer(unsigned long data); static void ace_tasklet(unsigned long dev); static void ace_dump_trace(struct ace_private *ap); static void ace_set_multicast_list(struct net_device *dev); static int ace_change_mtu(struct net_device *dev, int new_mtu); -#ifdef SKB_RECYCLE -extern int ace_recycle(struct sk_buff *skb); -#endif static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ace_set_mac_addr(struct net_device *dev, void *p); static void ace_set_rxtx_parms(struct net_device *dev, int jumbo); diff -u --recursive --new-file v2.4.3/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c --- v2.4.3/linux/drivers/net/am79c961a.c Tue Feb 13 13:15:04 2001 +++ linux/drivers/net/am79c961a.c Thu Apr 12 12:15:25 2001 @@ -637,7 +637,7 @@ static void __init am79c961_banner(void) { - static unsigned version_printed = 0; + static unsigned version_printed; if (net_debug && version_printed++ == 0) printk(KERN_INFO "%s", version); diff -u --recursive --new-file v2.4.3/linux/drivers/net/apne.c linux/drivers/net/apne.c --- v2.4.3/linux/drivers/net/apne.c Mon Nov 27 17:11:26 2000 +++ linux/drivers/net/apne.c Thu Apr 12 12:15:25 2001 @@ -119,7 +119,7 @@ static const char *version = "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n"; -static int apne_owned = 0; /* signal if card already owned */ +static int apne_owned; /* signal if card already owned */ int __init apne_probe(struct net_device *dev) { @@ -173,7 +173,7 @@ #ifndef MANUAL_HWADDR0 int neX000, ctron; #endif - static unsigned version_printed = 0; + static unsigned version_printed; static u32 pcmcia_offsets[16]={ 0, 1+GAYLE_ODD, 2, 3+GAYLE_ODD, 4, 5+GAYLE_ODD, 6, 7+GAYLE_ODD, diff -u --recursive --new-file v2.4.3/linux/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c --- v2.4.3/linux/drivers/net/appletalk/ipddp.c Sun Dec 3 17:45:22 2000 +++ linux/drivers/net/appletalk/ipddp.c Fri Apr 13 20:26:07 2001 @@ -20,12 +20,9 @@ * Director, National Security Agency. * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. */ -static const char *version = - "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; - #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -39,7 +36,9 @@ #include "ipddp.h" /* Our stuff */ -static struct ipddp_route *ipddp_route_list = NULL; +static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; + +static struct ipddp_route *ipddp_route_list; #ifdef CONFIG_IPDDP_ENCAP static int ipddp_mode = IPDDP_ENCAP; @@ -47,12 +46,6 @@ static int ipddp_mode = IPDDP_DECAP; #endif -/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ -#ifndef IPDDP_DEBUG -#define IPDDP_DEBUG 1 -#endif -static unsigned int ipddp_debug = IPDDP_DEBUG; - /* Index to functions, as function prototypes. */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *ipddp_get_stats(struct net_device *dev); @@ -64,12 +57,12 @@ static int __init ipddp_init(struct net_device *dev) { - static unsigned version_printed = 0; + static unsigned version_printed; SET_MODULE_OWNER(dev); - if (ipddp_debug && version_printed++ == 0) - printk("%s", version); + if (version_printed++ == 0) + printk(version); /* Let the user now what mode we are in */ if(ipddp_mode == IPDDP_ENCAP) @@ -193,25 +186,23 @@ static int ipddp_create(struct ipddp_route *new_rt) { struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL); - struct ipddp_route *test; - if(rt == NULL) + if (rt == NULL) return -ENOMEM; rt->ip = new_rt->ip; rt->at = new_rt->at; rt->next = NULL; - rt->dev = atrtr_get_dev(&rt->at); - if(rt->dev == NULL) - { - kfree(rt); - return (-ENETUNREACH); + if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) { + kfree(rt); + return -ENETUNREACH; } - test = ipddp_find_route(rt); - if(test != NULL) - return (-EEXIST); - + if (ipddp_find_route(rt)) { + kfree(rt); + return -EEXIST; + } + rt->next = ipddp_route_list; ipddp_route_list = rt; @@ -307,11 +298,16 @@ static void __exit ipddp_cleanup_module(void) { + struct ipddp_route *p; + unregister_netdev(&dev_ipddp); kfree(dev_ipddp.priv); - memset(&dev_ipddp, 0, sizeof(dev_ipddp)); - dev_ipddp.init = ipddp_init; + while (ipddp_route_list) { + p = ipddp_route_list->next; + kfree(ipddp_route_list); + ipddp_route_list = p; + } } module_init(ipddp_init_module); diff -u --recursive --new-file v2.4.3/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.4.3/linux/drivers/net/ariadne.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/ariadne.c Thu Apr 12 12:15:25 2001 @@ -121,7 +121,7 @@ }; #ifdef MODULE -static struct ariadne_private *root_ariadne_dev = NULL; +static struct ariadne_private *root_ariadne_dev; #endif static int ariadne_open(struct net_device *dev); diff -u --recursive --new-file v2.4.3/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c --- v2.4.3/linux/drivers/net/ariadne2.c Thu Jan 4 13:00:55 2001 +++ linux/drivers/net/ariadne2.c Thu Apr 12 12:15:25 2001 @@ -62,7 +62,7 @@ #define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) #ifdef MODULE -static struct net_device *root_ariadne2_dev = NULL; +static struct net_device *root_ariadne2_dev; #endif static const struct card_info { diff -u --recursive --new-file v2.4.3/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c --- v2.4.3/linux/drivers/net/arlan-proc.c Tue Mar 6 19:28:33 2001 +++ linux/drivers/net/arlan-proc.c Thu Apr 12 12:15:25 2001 @@ -1031,7 +1031,7 @@ -static struct ctl_table_header *arlan_device_sysctl_header = NULL; +static struct ctl_table_header *arlan_device_sysctl_header; int init_arlan_proc(void) { diff -u --recursive --new-file v2.4.3/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c --- v2.4.3/linux/drivers/net/atari_bionet.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/atari_bionet.c Thu Apr 12 12:15:25 2001 @@ -327,8 +327,8 @@ int __init bionet_probe(struct net_device *dev){ unsigned char station_addr[6]; - static unsigned version_printed = 0; - static int no_more_found = 0; /* avoid "Probing for..." printed 4 times */ + static unsigned version_printed; + static int no_more_found; /* avoid "Probing for..." printed 4 times */ int i; if (!MACH_IS_ATARI || no_more_found) diff -u --recursive --new-file v2.4.3/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c --- v2.4.3/linux/drivers/net/atari_pamsnet.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/atari_pamsnet.c Thu Apr 12 12:15:25 2001 @@ -569,9 +569,9 @@ HADDR *hwaddr; unsigned char station_addr[6]; - static unsigned version_printed = 0; + static unsigned version_printed; /* avoid "Probing for..." printed 4 times - the driver is supporting only one adapter now! */ - static int no_more_found = 0; + static int no_more_found; if (no_more_found) return -ENODEV; diff -u --recursive --new-file v2.4.3/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.4.3/linux/drivers/net/atp.c Tue Mar 6 19:28:33 2001 +++ linux/drivers/net/atp.c Thu Apr 12 12:15:25 2001 @@ -209,7 +209,7 @@ /* A list of all installed ATP devices, for removing the driver module. */ -static struct net_device *root_atp_dev = NULL; +static struct net_device *root_atp_dev; /* Check for a network adapter of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. @@ -584,7 +584,7 @@ struct net_device *dev = (struct net_device *)dev_instance; struct net_local *lp; long ioaddr; - static int num_tx_since_rx = 0; + static int num_tx_since_rx; int boguscount = max_interrupt_work; if (dev == NULL) { diff -u --recursive --new-file v2.4.3/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c --- v2.4.3/linux/drivers/net/bagetlance.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/bagetlance.c Thu Apr 12 12:15:25 2001 @@ -471,7 +471,7 @@ int __init bagetlance_probe( struct net_device *dev ) { int i; - static int found = 0; + static int found; SET_MODULE_OWNER(dev); @@ -519,7 +519,7 @@ struct lance_private *lp; struct lance_ioreg *IO; int i; - static int did_version = 0; + static int did_version; unsigned short save1, save2; PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", diff -u --recursive --new-file v2.4.3/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.4.3/linux/drivers/net/cs89x0.c Tue Mar 6 19:28:34 2001 +++ linux/drivers/net/cs89x0.c Thu Apr 12 12:16:35 2001 @@ -130,7 +130,6 @@ #include <asm/dma.h> #endif #include <linux/errno.h> -#include <linux/init.h> #include <linux/spinlock.h> #include <linux/netdevice.h> @@ -361,7 +360,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr) { struct net_local *lp; - static unsigned version_printed = 0; + static unsigned version_printed; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; @@ -1590,14 +1589,14 @@ * avoid breaking someone's startup scripts */ -static int io=0; -static int irq=0; -static int debug=0; +static int io; +static int irq; +static int debug; static char media[8]; static int duplex=-1; -static int use_dma = 0; /* These generate unused var warnings if ALLOW_DMA = 0 */ -static int dma=0; +static int use_dma; /* These generate unused var warnings if ALLOW_DMA = 0 */ +static int dma; static int dmasize=16; /* or 64 */ MODULE_PARM(io, "i"); diff -u --recursive --new-file v2.4.3/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c --- v2.4.3/linux/drivers/net/daynaport.c Sat Mar 3 10:55:47 2001 +++ linux/drivers/net/daynaport.c Thu Apr 12 12:15:25 2001 @@ -250,12 +250,12 @@ int __init mac8390_probe(struct net_device *dev) { - static int slots = 0; + static int slots; volatile unsigned short *i; volatile unsigned char *p; int plen; int id; - static struct nubus_dev* ndev = NULL; + static struct nubus_dev* ndev; /* Find the first card that hasn't already been seen */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, diff -u --recursive --new-file v2.4.3/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.4.3/linux/drivers/net/de4x5.c Tue Mar 6 19:28:35 2001 +++ linux/drivers/net/de4x5.c Fri Apr 13 20:26:07 2001 @@ -429,11 +429,17 @@ <mporter@eng.mcd.mot.com> Remove double checking for DEBUG_RX in de4x5_dbg_rx() from report by <geert@linux-m68k.org> - + 0.546 22-Feb-01 Fixes Alpha XP1000 oops. The srom_search function + was causing a page fault when initializing the + variable 'pb', on a non de4x5 PCI device, in this + case a PCI bridge (DEC chip 21152). The value of + 'pb' is now only initialized if a de4x5 chip is + present. + <france@handhelds.org> ========================================================================= */ -static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #include <linux/config.h> #include <linux/module.h> @@ -585,7 +591,7 @@ #ifdef DE4X5_PARM static char *args = DE4X5_PARM; #else -static char *args = NULL; +static char *args; #endif struct parameters { @@ -666,7 +672,7 @@ #define DESC_ALIGN #ifndef DEC_ONLY /* See README.de4x5 for using this */ -static int dec_only = 0; +static int dec_only; #else static int dec_only = 1; #endif @@ -1039,24 +1045,24 @@ MODULE_PARM(dec_only, "i"); MODULE_PARM(args, "s"); # else -static int loading_module = 0; +static int loading_module; #endif /* MODULE */ static char name[DE4X5_NAME_LENGTH + 1]; #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; -static int lastEISA = 0; +static int lastEISA; # ifdef DE4X5_FORCE_EISA /* Force an EISA bus probe or not */ static int forceEISA = 1; # else -static int forceEISA = 0; +static int forceEISA; # endif #endif -static int num_de4x5s = 0; -static int cfrv = 0, useSROM = 0; +static int num_de4x5s; +static int cfrv, useSROM; static int lastPCI = -1; -static struct net_device *lastModule = NULL; -static struct pci_dev *pdev = NULL; +static struct net_device *lastModule; +static struct pci_dev *pdev; /* ** List the SROM infoleaf functions and chipsets @@ -2304,12 +2310,12 @@ /* Skip the pci_bus list entry */ if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue; - pb = this_dev->bus->number; vendor = this_dev->vendor; device = this_dev->device << 8; if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; /* Get the chip configuration revision register */ + pb = this_dev->bus->number; pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv); /* Set the device number information */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.4.3/linux/drivers/net/de600.c Sat Mar 3 10:55:47 2001 +++ linux/drivers/net/de600.c Fri Apr 13 20:26:07 2001 @@ -265,14 +265,14 @@ /* * D-Link driver variables: */ -static volatile int rx_page = 0; +static volatile int rx_page; #define TX_PAGES 2 static volatile int tx_fifo[TX_PAGES]; -static volatile int tx_fifo_in = 0; -static volatile int tx_fifo_out = 0; +static volatile int tx_fifo_in; +static volatile int tx_fifo_out; static volatile int free_tx_pages = TX_PAGES; -static int was_down = 0; +static int was_down; /* * Convenience macros/functions for D-Link adapter @@ -597,7 +597,6 @@ } skb = dev_alloc_skb(size+2); - restore_flags(flags); if (skb == NULL) { printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size); diff -u --recursive --new-file v2.4.3/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v2.4.3/linux/drivers/net/de620.c Tue Mar 6 19:28:34 2001 +++ linux/drivers/net/de620.c Fri Apr 13 20:26:07 2001 @@ -183,8 +183,8 @@ * Make a clone skip the Ethernet-address range check: * insmod de620.o clone=1 */ -static int bnc = 0; -static int utp = 0; +static int bnc; +static int utp; static int io = DE620_IO; static int irq = DE620_IRQ; static int clone = DE620_CLONE; @@ -690,7 +690,6 @@ else { /* Yep! Go get it! */ skb_reserve(skb,2); /* Align */ skb->dev = dev; - skb->used = 0; /* skb->data points to the start of sk_buff data area */ buffer = skb_put(skb,size); /* copy the packet into the buffer */ @@ -722,7 +721,7 @@ static int adapter_init(struct net_device *dev) { int i; - static int was_down = 0; + static int was_down; if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */ EIPRegister = NCTL0; diff -u --recursive --new-file v2.4.3/linux/drivers/net/declance.c linux/drivers/net/declance.c --- v2.4.3/linux/drivers/net/declance.c Tue Mar 20 12:05:00 2001 +++ linux/drivers/net/declance.c Thu Apr 12 12:15:25 2001 @@ -1217,7 +1217,7 @@ /* Find all the lance cards on the system and initialize them */ static int __init dec_lance_probe(void) { - static int called = 0; + static int called; #ifdef MODULE root_lance_dev = NULL; diff -u --recursive --new-file v2.4.3/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.4.3/linux/drivers/net/depca.c Tue Mar 6 19:28:35 2001 +++ linux/drivers/net/depca.c Fri Apr 13 20:26:07 2001 @@ -1818,9 +1818,7 @@ ManCode[5]='\0'; for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) { - const char * volatile lhs = ManCode; - const char * volatile rhs = signatures[i]; /* egcs-1.1.2 bug */ - if (strstr(lhs, rhs) != NULL) { + if (strstr(ManCode, signatures[i]) != NULL) { strcpy(name,ManCode); status = 1; } diff -u --recursive --new-file v2.4.3/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.4.3/linux/drivers/net/dgrs.c Tue Mar 6 19:28:35 2001 +++ linux/drivers/net/dgrs.c Thu Apr 12 12:15:25 2001 @@ -174,7 +174,7 @@ static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; static __u32 dgrs_ipxnet = -1; -static int dgrs_nicmode = 0; +static int dgrs_nicmode; /* * Chain of device structures diff -u --recursive --new-file v2.4.3/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.4.3/linux/drivers/net/e2100.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/e2100.c Thu Apr 12 12:15:25 2001 @@ -140,7 +140,7 @@ { int i, status, retval; unsigned char *station_addr = dev->dev_addr; - static unsigned version_printed = 0; + static unsigned version_printed; if (!request_region(ioaddr, E21_IO_EXTENT, dev->name)) return -EBUSY; diff -u --recursive --new-file v2.4.3/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c --- v2.4.3/linux/drivers/net/ethertap.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/ethertap.c Thu Apr 12 12:15:25 2001 @@ -43,7 +43,7 @@ static void set_multicast_list(struct net_device *dev); #endif -static int ethertap_debug = 0; +static int ethertap_debug; static struct net_device *tap_map[32]; /* Returns the tap device for a given netlink */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.4.3/linux/drivers/net/ewrk3.c Sat Mar 3 10:55:48 2001 +++ linux/drivers/net/ewrk3.c Thu Apr 12 12:15:25 2001 @@ -330,12 +330,12 @@ #else static u_char irq[] = {5, 0, 10, 3, 11, 9, 15, 12}; -static int autoprobed = 0, loading_module = 0; +static int autoprobed, loading_module; #endif /* MODULE */ static char name[EWRK3_STRLEN + 1]; -static int num_ewrk3s = 0, num_eth = 0; +static int num_ewrk3s, num_eth; /* ** Miscellaneous defines... diff -u --recursive --new-file v2.4.3/linux/drivers/net/gt96100eth.c linux/drivers/net/gt96100eth.c --- v2.4.3/linux/drivers/net/gt96100eth.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/gt96100eth.c Fri Apr 13 20:26:07 2001 @@ -0,0 +1,1253 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.com + * + * ######################################################################## + * + * 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. + * + * ######################################################################## + * + * Ethernet driver for the MIPS GT96100 Advanced Communication Controller. + * + */ + +#ifndef __mips__ +#error This driver only works with MIPS architectures! +#endif + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/in.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/io.h> + +#include "gt96100eth.h" + +#ifdef GT96100_DEBUG +static int gt96100_debug = GT96100_DEBUG; +#else +static int gt96100_debug = 3; +#endif + +// prototypes +static void *dmaalloc(size_t size, dma_addr_t * dma_handle); +static void dmafree(size_t size, void *vaddr); +static int gt96100_add_hash_entry(struct net_device *dev, + unsigned char *addr); +static void read_mib_counters(struct gt96100_private *gp); +static int read_MII(struct net_device *dev, u32 reg); +static int write_MII(struct net_device *dev, u32 reg, u16 data); +static void dump_MII(struct net_device *dev); +static void update_stats(struct gt96100_private *gp); +static void abort(struct net_device *dev, u32 abort_bits); +static void hard_stop(struct net_device *dev); +static void enable_ether_irq(struct net_device *dev); +static void disable_ether_irq(struct net_device *dev); +static int __init gt96100_probe1(struct net_device *dev, long ioaddr, + int irq, int port_num); +static int gt96100_init(struct net_device *dev); +static int gt96100_open(struct net_device *dev); +static int gt96100_close(struct net_device *dev); +static int gt96100_tx(struct sk_buff *skb, struct net_device *dev); +static int gt96100_rx(struct net_device *dev, u32 status); +static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void gt96100_tx_timeout(struct net_device *dev); +static void gt96100_set_rx_mode(struct net_device *dev); +static struct net_device_stats *gt96100_get_stats(struct net_device *dev); + +static char version[] __devinitdata = + "gt96100eth.c:0.1 stevel@mvista.com\n"; + +// FIX! Need real Ethernet addresses +static unsigned char gt96100_station_addr[2][6] __devinitdata = + { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, +{0x01, 0x02, 0x03, 0x04, 0x05, 0x07} +}; + +#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) + +#define RUN_AT(x) (jiffies + (x)) + +// For reading/writing 32-bit words from/to DMA memory +#define cpu_to_dma32 cpu_to_be32 +#define dma32_to_cpu be32_to_cpu + +/* + * Base address and interupt of the GT96100 ethernet controllers + */ +static struct { + unsigned int port; + int irq; +} gt96100_iflist[NUM_INTERFACES] = { + { + GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, { + GT96100_ETH1_BASE, GT96100_ETHER1_IRQ} +}; + +/* + DMA memory allocation, derived from pci_alloc_consistent. +*/ +static void *dmaalloc(size_t size, dma_addr_t * dma_handle) +{ + void *ret; + + ret = + (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, + get_order(size)); + + if (ret != NULL) { + dma_cache_inv((unsigned long) ret, size); + if (dma_handle != NULL) + *dma_handle = virt_to_phys(ret); + + /* bump virtual address up to non-cached area */ + ret = KSEG1ADDR(ret); + } + + return ret; +} + +static void dmafree(size_t size, void *vaddr) +{ + vaddr = KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static int read_MII(struct net_device *dev, u32 reg) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int timedout = 20; + u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) | + (reg << smirRegAdBit); + + // wait for last operation to complete + while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { + // snooze for 1 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: read_MII busy timeout!!\n", + dev->name); + return -1; + } + } + + GT96100_WRITE(GT96100_ETH_SMI_REG, smir); + + timedout = 20; + // wait for read to complete + while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) { + // snooze for 1 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: read_MII timeout!!\n", + dev->name); + return -1; + } + } + + return (int) (smir & smirDataMask); +} + +static int write_MII(struct net_device *dev, u32 reg, u16 data) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int timedout = 20; + u32 smir = + (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data; + + // wait for last operation to complete + while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { + // snooze for 1 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: write_MII busy timeout!!\n", + dev->name); + return -1; + } + } + + GT96100_WRITE(GT96100_ETH_SMI_REG, smir); + return 0; +} + + +static void dump_MII(struct net_device *dev) +{ + int i, val; + + for (i = 0; i < 7; i++) { + if ((val = read_MII(dev, i)) >= 0) + printk("%s: MII Reg %d=%x\n", dev->name, i, val); + } + for (i = 16; i < 21; i++) { + if ((val = read_MII(dev, i)) >= 0) + printk("%s: MII Reg %d=%x\n", dev->name, i, val); + } +} + + +static int +gt96100_add_hash_entry(struct net_device *dev, unsigned char *addr) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u16 hashResult, stmp; + unsigned char ctmp, hash_ea[6]; + u32 tblEntry, *tblEntryAddr; + int i; + + for (i = 0; i < 6; i++) { + // nibble swap + ctmp = nibswap(addr[i]); + // invert every nibble + hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) | + ((ctmp & 2) << 1) | ((ctmp & 4) >> 1); + hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) | + ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1); + } + + if (gp->hash_mode == 0) { + hashResult = ((u16) hash_ea[0] & 0xfc) << 7; + stmp = + ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f) + << 2); + stmp ^= + (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] << + 1); + stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8); + hashResult |= stmp; + } else { + return -1; // don't support hash mode 1 + } + + tblEntryAddr = + (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]); + + for (i = 0; i < HASH_HOP_NUMBER; i++) { + if ((*tblEntryAddr & hteValid) + && !(*tblEntryAddr & hteSkip)) { + // This entry is already occupied, go to next entry + tblEntryAddr += 2; + } else { + memset(tblEntryAddr, 0, 8); + tblEntry = hteValid | hteRD; + tblEntry |= (u32) addr[5] << 3; + tblEntry |= (u32) addr[4] << 11; + tblEntry |= (u32) addr[3] << 19; + tblEntry |= ((u32) addr[2] & 0x1f) << 27; + *(tblEntryAddr + 1) = cpu_to_dma32(tblEntry); + tblEntry = ((u32) addr[2] >> 5) & 0x07; + tblEntry |= (u32) addr[1] << 3; + tblEntry |= (u32) addr[0] << 11; + *tblEntryAddr = cpu_to_dma32(tblEntry); + break; + } + } + + if (i >= HASH_HOP_NUMBER) { + printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n", + dev->name); + return -1; // Couldn't find an unused entry + } + + return 0; +} + + +static void read_mib_counters(struct gt96100_private *gp) +{ + u32 *mib_regs = (u32 *) & gp->mib; + int i; + + for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++) + mib_regs[i] = + GT96100ETH_READ(gp, + GT96100_ETH_MIB_COUNT_BASE + + i * sizeof(u32)); +} + + +static void update_stats(struct gt96100_private *gp) +{ + mib_counters_t *mib = &gp->mib; + struct net_device_stats *stats = &gp->stats; + + read_mib_counters(gp); + + stats->rx_packets = mib->totalFramesReceived; + stats->tx_packets = mib->framesSent; + stats->rx_bytes = mib->totalByteReceived; + stats->tx_bytes = mib->byteSent; + stats->rx_errors = mib->totalFramesReceived - mib->framesReceived; + //the tx error counters are incremented by the ISR + //rx_dropped incremented by gt96100_rx + //tx_dropped incremented by gt96100_tx + stats->multicast = mib->multicastFramesReceived; + // Tx collisions incremented by ISR, so add in MIB Rx collisions + stats->collisions += mib->collision + mib->lateCollision; + stats->rx_length_errors = mib->oversizeFrames + mib->fragments; + // The RxError condition means the Rx DMA encountered a + // CPU owned descriptor, which, if things are working as + // they should, means the Rx ring has overflowed. + stats->rx_over_errors = mib->macRxError; + stats->rx_crc_errors = mib->cRCError; +} + +static void abort(struct net_device *dev, u32 abort_bits) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int timedout = 100; // wait up to 100 msec for hard stop to complete + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: abort\n", dev->name); + + // Return if neither Rx or Tx abort bits are set + if (!(abort_bits & (sdcmrAR | sdcmrAT))) + return; + + // make sure only the Rx/Tx abort bits are set + abort_bits &= (sdcmrAR | sdcmrAT); + + spin_lock(&gp->lock); + + // abort any Rx/Tx DMA immediately + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits); + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: abort: SDMA comm = %x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_SDMA_COMM)); + + // wait for abort to complete + while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) { + // snooze for 20 msec and check again +#if 0 + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ / 10000); +#else + mdelay(1); +#endif + + if (--timedout == 0) { + printk(KERN_ERR "%s: abort timeout!!\n", + dev->name); + break; + } + } + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name, + timedout); + + spin_unlock(&gp->lock); +} + + +static void hard_stop(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: hard stop\n", dev->name); + + disable_ether_irq(dev); + + abort(dev, sdcmrAR | sdcmrAT); + + // disable port + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0); +} + + +static void enable_ether_irq(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u32 intMask; + + // unmask interrupts + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, + icrRxBuffer | icrTxBufferLow | icrTxEndLow | + icrRxError | icrTxErrorLow | icrRxOVR | + icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 | + icrMIIPhySTC); + + // now route ethernet interrupts to GT Int0 (eth0 and eth1 will be + // sharing it). + // FIX! The kernel's irq code should do this + intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); + intMask |= 1 << gp->port_num; + GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); +} + +static void disable_ether_irq(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u32 intMask; + + // FIX! The kernel's irq code should do this + intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); + intMask &= ~(1 << gp->port_num); + GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); + + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0); +} + + +/* + * Probe for a GT96100 ethernet controller. + */ +int __init gt96100_probe(struct net_device *dev) +{ + unsigned int base_addr = dev ? dev->base_addr : 0; + int i; + +#ifndef CONFIG_MIPS_GT96100ETH + return -ENODEV; +#endif + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: gt96100_probe\n", dev->name); + + if (base_addr >= KSEG0) /* Check a single specified location. */ + return gt96100_probe1(dev, base_addr, dev->irq, 0); + else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + +// for (i = 0; i<NUM_INTERFACES; i++) { + for (i = NUM_INTERFACES - 1; i >= 0; i--) { + int base_addr = gt96100_iflist[i].port; +#if 0 + if (check_region(base_addr, GT96100_ETH_IO_SIZE)) { + printk(KERN_ERR + "%s: gt96100_probe: ioaddr 0x%lx taken?\n", + dev->name, base_addr); + continue; + } +#endif + if (gt96100_probe1 + (dev, base_addr, gt96100_iflist[i].irq, i) == 0) + return 0; + } + return -ENODEV; +} + + + +static int __init +gt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +{ + static unsigned version_printed = 0; + struct gt96100_private *gp = NULL; + int i, retval; + u32 cpuConfig; + + // FIX! probe for GT96100 by reading a suitable register + + if (gt96100_debug > 2) + printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n", + ioaddr, irq); + + request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH"); + + cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); + if (cpuConfig & (1 << 12)) { + printk(KERN_ERR + "gt96100_probe1: must be in Big Endian mode!\n"); + retval = -ENODEV; + goto free_region; + } + + if (gt96100_debug > 2) + printk(KERN_INFO + "gt96100_probe1: chip in Big Endian mode - cool\n"); + + /* Allocate a new 'dev' if needed. */ + if (dev == NULL) + dev = init_etherdev(0, sizeof(struct gt96100_private)); + + if (gt96100_debug && version_printed++ == 0) + printk(version); + + if (irq < 0) { + printk(KERN_ERR + "gt96100_probe1: irq unknown - probing not supported\n"); + retval = -ENODEV; + goto free_region; + } + + printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n", + dev->name, ioaddr, irq); + + /* private struct aligned and zeroed by init_etherdev */ + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + dev->irq = irq; + memcpy(dev->dev_addr, gt96100_station_addr[port_num], + sizeof(dev->dev_addr)); + + printk(KERN_INFO "%s: HW Address ", dev->name); + for (i = 0; i < sizeof(dev->dev_addr); i++) { + printk("%2.2x", dev->dev_addr[i]); + printk(i < 5 ? ":" : "\n"); + } + + /* Initialize our private structure. */ + if (dev->priv == NULL) { + + gp = + (struct gt96100_private *) kmalloc(sizeof(*gp), + GFP_KERNEL); + if (gp == NULL) { + retval = -ENOMEM; + goto free_region; + } + + dev->priv = gp; + } + + gp = dev->priv; + + memset(gp, 0, sizeof(*gp)); // clear it + + gp->port_num = port_num; + gp->io_size = GT96100_ETH_IO_SIZE; + gp->port_offset = port_num * GT96100_ETH_IO_SIZE; + gp->phy_addr = port_num + 1; + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: gt96100_probe1, port %d\n", + dev->name, gp->port_num); + + // Allocate Rx and Tx descriptor rings + if (gp->rx_ring == NULL) { + // All descriptors in ring must be 16-byte aligned + gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE + + + sizeof(gt96100_td_t) * TX_RING_SIZE, + &gp->rx_ring_dma); + if (gp->rx_ring == NULL) { + retval = -ENOMEM; + goto free_region; + } + + gp->tx_ring = + (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE); + gp->tx_ring_dma = + gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; + } + + if (gt96100_debug > 2) + printk(KERN_INFO + "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n", + dev->name, gp->rx_ring, gp->tx_ring); + + // Allocate Rx Hash Table + if (gp->hash_table == NULL) { + gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE, + &gp->hash_table_dma); + if (gp->hash_table == NULL) { + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + retval = -ENOMEM; + goto free_region; + } + } + + if (gt96100_debug > 2) + printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n", + dev->name, gp->hash_table); + + spin_lock_init(&gp->lock); + + dev->open = gt96100_open; + dev->hard_start_xmit = gt96100_tx; + dev->stop = gt96100_close; + dev->get_stats = gt96100_get_stats; + //dev->do_ioctl = gt96100_ioctl; + dev->set_multicast_list = gt96100_set_rx_mode; + dev->tx_timeout = gt96100_tx_timeout; + dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; + + free_region: + release_region(ioaddr, gp->io_size); + unregister_netdev(dev); + if (dev->priv != NULL) + kfree(dev->priv); + kfree(dev); + printk(KERN_ERR "%s: gt96100_probe1 failed. Returns %d\n", + dev->name, retval); + return retval; +} + + +static int gt96100_init(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + u32 phyAD, ciu; + int i; + + if (gt96100_debug > 2) + printk("%s: gt96100_init: dev=%p\n", dev->name, dev); + + // Stop and disable Port + hard_stop(dev); + + spin_lock_irqsave(&gp->lock, flags); + + // First things first, set-up hash table + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it + gp->hash_mode = 0; + // Add a single entry to hash table - our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + // Set-up DMA ptr to hash table + GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); + if (gt96100_debug > 2) + printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); + + // Setup Tx descriptor ring + for (i = 0; i < TX_RING_SIZE; i++) { + gp->tx_ring[i].cmdstat = 0; // CPU owns + gp->tx_ring[i].byte_cnt = 0; + gp->tx_ring[i].buff_ptr = 0; + gp->tx_ring[i].next = + cpu_to_dma32(gp->tx_ring_dma + + sizeof(gt96100_td_t) * (i + 1)); + } + /* Wrap the ring. */ + gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma); + + // setup only the lowest priority TxCDP reg + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, + gp->tx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0); + if (gt96100_debug > 2) + printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_CURR_TX_DESC_PTR0)); + + // Setup Rx descriptor ring + for (i = 0; i < RX_RING_SIZE; i++) { + dma_addr_t rx_buff_dma; + gp->rx_ring[i].next = + cpu_to_dma32(gp->rx_ring_dma + + sizeof(gt96100_rd_t) * (i + 1)); + if (gp->rx_buff[i] == NULL) + gp->rx_buff[i] = + dmaalloc(PKT_BUF_SZ, &rx_buff_dma); + else + rx_buff_dma = virt_to_phys(gp->rx_buff[i]); + if (gp->rx_buff[i] == NULL) + break; + gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma); + gp->rx_ring[i].buff_cnt_sz = + cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit); + // Give ownership to device, enable interrupt + gp->rx_ring[i].cmdstat = + cpu_to_dma32((u32) (rxOwn | rxEI)); + } + + if (i != RX_RING_SIZE) { + int j; + for (j = 0; j < RX_RING_SIZE; j++) { + if (gp->rx_buff[j]) { + dmafree(PKT_BUF_SZ, gp->rx_buff[j]); + gp->rx_buff[j] = NULL; + } + } + printk(KERN_ERR "%s: Rx ring allocation failed.\n", + dev->name); + spin_unlock_irqrestore(&gp->lock, flags); + return -ENOMEM; + } + + /* Wrap the ring. */ + gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma); + + // Set our MII PHY device address + phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); + phyAD &= ~(0x1f << (gp->port_num * 5)); + phyAD |= gp->phy_addr << (gp->port_num * 5); + GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); + + if (gt96100_debug > 2) + printk("%s: gt96100_init: PhyAD=%x\n", dev->name, + GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); + + // Clear all the RxFDP and RXCDP regs... + for (i = 0; i < 4; i++) { + GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4, + 0); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4, + 0); + } + // and setup only the lowest priority RxFDP and RxCDP regs + GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, + gp->rx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, + gp->rx_ring_dma); + if (gt96100_debug > 2) + printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_1ST_RX_DESC_PTR0), + GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); + + // init Rx/Tx indeces and pkt counters + gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0; + gp->tx_count = 0; + + // setup DMA + + // FIX! this should be done by Kernel setup code + ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); + ciu |= (0x0c << (gp->port_num * 2)); // set Ether DMA req priority to high + // FIX! setting the following bit causes the EV96100 board to hang!!! + //ciu |= (1 << (24+gp->port_num)); // pull Ethernet port out of Reset??? + // FIX! endian mode??? + ciu &= ~(1 << 31); // set desc endianess to Big + GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu); + if (gt96100_debug > 2) + printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name, + ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); + + // We want the Rx/Tx DMA to write/read data to/from memory in + // Big Endian mode. Also set DMA Burst Size to 8 64Bit words. + // FIX! endian mode??? + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG, + //sdcrBLMR | sdcrBLMT | + (0xf << sdcrRCBit) | sdcrRIFB | (3 << sdcrBSZBit)); + if (gt96100_debug > 2) + printk("%s: gt96100_init: SDMA Config=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG)); + + // start Rx DMA + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); + if (gt96100_debug > 2) + printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); + + // enable interrupts + enable_ether_irq(dev); + + /* + * Disable all Type-of-Service queueing. All Rx packets will be + * treated normally and will be sent to the lowest priority + * queue. + * + * Disable flow-control for now. FIX! support flow control? + */ + // clear all the MIB ctr regs + // Enable reg clear on read. FIX! desc of this bit is inconsistent + // in the GT-96100A datasheet. + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, + pcxrFCTL | pcxrFCTLen | pcxrFLP); + read_mib_counters(gp); + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, + pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode); + + if (gt96100_debug > 2) + printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); + + // enable this port (set hash size to 1/2K) + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); + if (gt96100_debug > 2) + printk("%s: gt96100_init: Port Config=%x\n", dev->name, + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); + + // we should now be receiving frames + if (gt96100_debug > 2) + dump_MII(dev); + + spin_unlock_irqrestore(&gp->lock, flags); + return 0; +} + + +static int gt96100_open(struct net_device *dev) +{ + int retval; + + MOD_INC_USE_COUNT; + + if (gt96100_debug > 2) + printk("%s: gt96100_open: dev=%p\n", dev->name, dev); + + if ((retval = request_irq(dev->irq, >96100_interrupt, + SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, + dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + // Initialize and startup the GT-96100 ethernet port + if ((retval = gt96100_init(dev))) { + printk(KERN_ERR "%s: error in gt96100_init\n", dev->name); + free_irq(dev->irq, dev); + MOD_DEC_USE_COUNT; + return retval; + } + + netif_start_queue(dev); + + if (gt96100_debug > 2) + printk("%s: gt96100_open: Initialization done.\n", + dev->name); + + return 0; +} + +static int gt96100_close(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + int i; + + if (gt96100_debug > 2) + printk("%s: gt96100_close: dev=%p\n", dev->name, dev); + + // stop the device + if (netif_device_present(dev)) { + netif_stop_queue(dev); + hard_stop(dev); + } + // free the Rx DMA buffers + for (i = 0; i < RX_RING_SIZE; i++) { + if (gp->rx_buff[i]) { + dmafree(PKT_BUF_SZ, gp->rx_buff[i]); + gp->rx_buff[i] = NULL; + } + } + + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + return 0; +} + + +static int gt96100_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + int nextIn; + + if (gt96100_debug > 2) + printk("%s: gt96100_tx: skb->len=%d, skb->data=%p\n", + dev->name, skb->len, skb->data); + + spin_lock_irqsave(&gp->lock, flags); + + if (gp->tx_count >= TX_RING_SIZE) { + printk(KERN_WARNING + "%s: Tx Ring full, refusing to send buffer.\n", + dev->name); + gp->stats.tx_dropped++; + spin_unlock_irqrestore(&gp->lock, flags); + return 1; + } + // Prepare the Descriptor at tx_next_in + nextIn = gp->tx_next_in; + + if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) { + printk(KERN_ERR "%s: gt96100_tx: TxOwn bit wrong!!\n", + dev->name); + } + + gp->tx_skbuff[nextIn] = skb; + gp->tx_ring[nextIn].byte_cnt = + cpu_to_dma32(skb->len << tdByteCntBit); + gp->tx_ring[nextIn].buff_ptr = + cpu_to_dma32(virt_to_phys(skb->data)); + // Give ownership to device, set first and last desc, enable interrupt + // Setting of ownership bit must be *last*! + gp->tx_ring[nextIn].cmdstat = + cpu_to_dma32((u32) (txOwn | txEI | txFirst | txLast)); + + // increment tx_next_in with wrap + gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE; + // If count is zero, DMA should be stopped, so restart + if (gp->tx_count == 0) { + if (GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & + psrTxLow) printk(KERN_WARNING + "%s: Tx count zero but Tx queue running!\n", + dev->name); + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, + sdcmrERD | sdcmrTXDL); + } + // increment count and stop queue if full + if (++gp->tx_count == TX_RING_SIZE) + netif_stop_queue(dev); + + dev->trans_start = jiffies; + spin_unlock_irqrestore(&gp->lock, flags); + + return 0; +} + + +static int gt96100_rx(struct net_device *dev, u32 status) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct sk_buff *skb; + int pkt_len, nextOut; + gt96100_rd_t *rd; + u32 cmdstat; + + if (gt96100_debug > 2) + printk("%s: gt96100_rx: dev=%p, status = %x\n", + dev->name, dev, status); + + // Continue until we reach the current descriptor pointer + for (nextOut = gp->rx_next_out; + nextOut != + (GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0) - + gp->rx_ring_dma) / sizeof(gt96100_rd_t); + nextOut = (nextOut + 1) % RX_RING_SIZE) { + + rd = &gp->rx_ring[nextOut]; + cmdstat = dma32_to_cpu(rd->cmdstat); + + if (cmdstat & (u32) rxOwn) { + cmdstat &= ~((u32) rxOwn); + rd->cmdstat = cpu_to_dma32(cmdstat); + printk(KERN_ERR + "%s: gt96100_rx: ownership bit wrong!\n", + dev->name); + } + // must be first and last (ie only) buffer of packet + if (!(cmdstat & (u32) rxFirst) + || !(cmdstat & (u32) rxLast)) { + printk(KERN_ERR + "%s: gt96100_rx: desc not first and last!\n", + dev->name); + continue; + } + // drop this received pkt if there were any errors + if ((cmdstat & (u32) rxErrorSummary) + || (status & icrRxErrorQ0)) { + // update the detailed rx error counters that are not covered + // by the MIB counters. + if (cmdstat & (u32) rxOverrun) + gp->stats.rx_fifo_errors++; + continue; + } + + pkt_len = dma32_to_cpu(rd->buff_cnt_sz) & rdByteCntMask; + + /* Create new skb. */ + skb = dev_alloc_skb(pkt_len + 2); + if (skb == NULL) { + printk(KERN_ERR + "%s: Memory squeeze, dropping packet.\n", + dev->name); + gp->stats.rx_dropped++; + continue; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte IP header align */ + skb_put(skb, pkt_len); /* Make room */ + eth_copy_and_sum(skb, gp->rx_buff[nextOut], pkt_len, 0); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); /* pass the packet to upper layers */ + + // now we can release ownership of this desc back to device + cmdstat |= (u32) rxOwn; + rd->cmdstat = cpu_to_dma32(cmdstat); + + dev->last_rx = jiffies; + } + + gp->rx_next_out = nextOut; + return 0; +} + + +static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + u32 status; + + if (dev == NULL) { + printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); + return; + } + + status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE); + // ACK interrupts +#if 0 + GT96100ETH_CLRBIT(gp, GT96100_ETH_INT_CAUSE, + icrEtherIntSum | icrRxBufferQ1 | icrRxBufferQ2 | + icrRxBufferQ3 | icrRxBufferQ0 | icrTxBufferHigh | + icrTxEndHigh | icrTxBufferLow | icrTxEndLow | + icrTxErrorHigh | icrTxErrorLow | icrTxUdr); +#else + GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0); +#endif + + if ((status & icrEtherIntSum) == 0) { + // not our interrupt + //printk("%s: isr: no ints? icr=%x,cp0_cause=%x\n", + // dev->name, status, read_32bit_cp0_register(CP0_CAUSE)); + return; + } + + if (gt96100_debug > 3) + printk("%s: isr: entry, icr=%x\n", dev->name, status); + + if (status & (icrRxBufferQ1 | icrRxBufferQ2 | icrRxBufferQ3)) { + printk(KERN_ERR "%s: isr: Rx intr in unused queues!?\n", + dev->name); + } + + if (status & icrRxBufferQ0) { + gt96100_rx(dev, status); + } + + if (status & (icrTxBufferHigh | icrTxEndHigh)) { + printk(KERN_ERR "%s: isr: Tx intr in unused queue!?\n", + dev->name); + } + + if (status & icrMIIPhySTC) { + u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS); + printk("%s: port status:\n", dev->name); + printk + ("%s: %s MBit/s, %s-duplex, flow-control %s, link is %s,\n", + dev->name, psr & psrSpeed ? "100" : "10", + psr & psrDuplex ? "full" : "half", + psr & psrFctl ? "disabled" : "enabled", + psr & psrLink ? "up" : "down"); + printk + ("%s: TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n", + dev->name, psr & psrTxLow ? "running" : "stopped", + psr & psrTxHigh ? "running" : "stopped", + psr & psrTxInProg ? "on" : "off"); + gp->last_psr = psr; + } + + if (status & (icrTxBufferLow | icrTxEndLow)) { + int nextOut; + gt96100_td_t *td; + u32 cmdstat; + + // Continue until we reach the current descriptor pointer + for (nextOut = gp->tx_next_out; + nextOut != + (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) - + gp->tx_ring_dma) / sizeof(gt96100_td_t); + nextOut = (nextOut + 1) % TX_RING_SIZE) { + + td = &gp->tx_ring[nextOut]; + cmdstat = dma32_to_cpu(td->cmdstat); + + if (gt96100_debug > 2) + printk("%s: isr: Tx desc cmdstat=%x\n", + dev->name, cmdstat); + + if (cmdstat & (u32) txOwn) { + cmdstat &= ~((u32) txOwn); + td->cmdstat = cpu_to_dma32(cmdstat); + printk(KERN_ERR + "%s: isr: Tx ownership bit wrong!\n", + dev->name); + } + // increment Tx error stats + if (cmdstat & (u32) txErrorSummary) { + if (gt96100_debug > 2) + printk + ("%s: gt96100_interrupt: Tx error, cmdstat = %x\n", + dev->name, cmdstat); + gp->stats.tx_errors++; + if (cmdstat & (u32) txReTxLimit) + gp->stats.collisions++; + if (cmdstat & (u32) txUnderrun) + gp->stats.tx_fifo_errors++; + if (cmdstat & (u32) txLateCollision) + gp->stats.tx_window_errors++; + } + // Wake the queue if the ring was full + if (gp->tx_count == TX_RING_SIZE) + netif_wake_queue(dev); + + // decrement tx ring buffer count + if (gp->tx_count) + gp->tx_count--; + + // free the skb + if (gp->tx_skbuff[nextOut]) { + if (gt96100_debug > 2) + printk + ("%s: isr: good Tx, skb=%p\n", + dev->name, + gp->tx_skbuff[nextOut]); + dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); + gp->tx_skbuff[nextOut] = NULL; + } else { + printk(KERN_ERR "%s: isr: no skb!\n", + dev->name); + } + } + + if (gp->tx_count == 0 && nextOut != gp->tx_next_in) { + // FIX! this should probably be a panic + printk(KERN_ERR + "%s: isr: warning! Tx queue inconsistent\n", + dev->name); + } + + gp->tx_next_out = nextOut; + + if ((status & icrTxEndLow) && gp->tx_count != 0) { + // we must restart the DMA + if (gt96100_debug > 2) + printk("%s: isr: Restarting Tx DMA\n", + dev->name); + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, + sdcmrERD | sdcmrTXDL); + } + } + // Now check TX errors (RX errors were handled in gt96100_rx) + + if (status & icrTxErrorHigh) { + printk(KERN_ERR + "%s: isr: Tx resource error in unused queue!?\n", + dev->name); + } + + if (status & icrTxErrorLow) { + printk(KERN_ERR "%s: isr: Tx resource error\n", dev->name); + } + + if (status & icrTxUdr) { + printk(KERN_ERR "%s: isr: Tx underrun error\n", dev->name); + } + + if (gt96100_debug > 3) + printk("%s: isr: exit, icr=%x\n", + dev->name, GT96100ETH_READ(gp, + GT96100_ETH_INT_CAUSE)); +} + + +/* + * The Tx ring has been full longer than the watchdog timeout + * value, meaning that the interrupt routine has not been freeing + * up space in the Tx ring buffer. + */ +static void gt96100_tx_timeout(struct net_device *dev) +{ +// struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + + printk(KERN_ERR "%s: gt96100_tx_timeout: dev=%p\n", dev->name, + dev); + + // FIX! do something, like reset the device +} + + +static void gt96100_set_rx_mode(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + struct dev_mc_list *mcptr; + + if (gt96100_debug > 2) + printk("%s: gt96100_set_rx_mode: dev=%p, flags=%x\n", + dev->name, dev, dev->flags); + + // stop the Receiver DMA + abort(dev, sdcmrAR); + + spin_lock_irqsave(&gp->lock, flags); + + if (dev->flags & IFF_PROMISC) + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, + pcrEN | pcrHS | pcrPM); + + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear hash table + // Add our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + + if (dev->mc_count) { + for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) { + gt96100_add_hash_entry(dev, mcptr->dmi_addr); + } + } + // restart Rx DMA + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); + + spin_unlock_irqrestore(&gp->lock, flags); +} + +static struct net_device_stats *gt96100_get_stats(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + unsigned long flags; + + if (gt96100_debug > 2) + printk("%s: gt96100_get_stats: dev=%p\n", dev->name, dev); + + if (netif_device_present(dev)) { + spin_lock_irqsave(&gp->lock, flags); + update_stats(gp); + spin_unlock_irqrestore(&gp->lock, flags); + } + + return &gp->stats; +} + +module_init(gt96100_probe); diff -u --recursive --new-file v2.4.3/linux/drivers/net/gt96100eth.h linux/drivers/net/gt96100eth.h --- v2.4.3/linux/drivers/net/gt96100eth.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/gt96100eth.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,326 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or support@mvista.com + * + * ######################################################################## + * + * 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. + * + * ######################################################################## + * + * Ethernet driver definitions for the MIPS GT96100 Advanced + * Communication Controller. + * + */ +#ifndef _GT96100ETH_H +#define _GT96100ETH_H + +#include <linux/config.h> +#include <asm/galileo-boards/gt96100.h> + +/* Keep the ring sizes a power of two for efficiency. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + +#define RX_HASH_TABLE_SIZE 16384 +#define HASH_HOP_NUMBER 12 + +#define NUM_INTERFACES 2 + +#define GT96100ETH_TX_TIMEOUT HZ + +#define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG) +#define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE) + +#ifdef CONFIG_MIPS_EV96100 +#define GT96100_ETHER0_IRQ 4 +#define GT96100_ETHER1_IRQ 4 +#else +#define GT96100_ETHER0_IRQ -1 +#define GT96100_ETHER1_IRQ -1 +#endif + +#define GT96100ETH_READ(gp, offset) \ + GT96100_READ((gp->port_offset + offset)) + +#define GT96100ETH_WRITE(gp, offset, data) \ + GT96100_WRITE((gp->port_offset + offset), data) + +#define GT96100ETH_SETBIT(gp, offset, bits) {\ + u32 val = GT96100ETH_READ(gp, offset); val |= (u32)(bits); \ + GT96100ETH_WRITE(gp, offset, val); } + +#define GT96100ETH_CLRBIT(gp, offset, bits) {\ + u32 val = GT96100ETH_READ(gp, offset); val &= (u32)(~(bits)); \ + GT96100ETH_WRITE(gp, offset, val); } + + +/* Bit definitions of the SMI Reg */ +enum { + smirDataMask = 0xffff, + smirPhyAdMask = 0x1f << 16, + smirPhyAdBit = 16, + smirRegAdMask = 0x1f << 21, + smirRegAdBit = 21, + smirOpCode = 1 << 26, + smirReadValid = 1 << 27, + smirBusy = 1 << 28 +}; + +/* Bit definitions of the Port Config Reg */ +enum pcr_bits { + pcrPM = 1, + pcrRBM = 2, + pcrPBF = 4, + pcrEN = 1 << 7, + pcrLPBKMask = 0x3 << 8, + pcrLPBKBit = 8, + pcrFC = 1 << 10, + pcrHS = 1 << 12, + pcrHM = 1 << 13, + pcrHDM = 1 << 14, + pcrHD = 1 << 15, + pcrISLMask = 0x7 << 28, + pcrISLBit = 28, + pcrACCS = 1 << 31 +}; + +/* Bit definitions of the Port Config Extend Reg */ +enum pcxr_bits { + pcxrIGMP = 1, + pcxrSPAN = 2, + pcxrPAR = 4, + pcxrPRIOtxMask = 0x7 << 3, + pcxrPRIOtxBit = 3, + pcxrPRIOrxMask = 0x3 << 6, + pcxrPRIOrxBit = 6, + pcxrPRIOrxOverride = 1 << 8, + pcxrDPLXen = 1 << 9, + pcxrFCTLen = 1 << 10, + pcxrFLP = 1 << 11, + pcxrFCTL = 1 << 12, + pcxrMFLMask = 0x3 << 14, + pcxrMFLBit = 14, + pcxrMIBclrMode = 1 << 16, + pcxrSpeed = 1 << 18, + pcxrSpeeden = 1 << 19, + pcxrRMIIen = 1 << 20, + pcxrDSCPen = 1 << 21 +}; + +/* Bit definitions of the Port Command Reg */ +enum pcmr_bits { + pcmrFJ = 1 << 15 +}; + + +/* Bit definitions of the Port Status Reg */ +enum psr_bits { + psrSpeed = 1, + psrDuplex = 2, + psrFctl = 4, + psrLink = 8, + psrPause = 1 << 4, + psrTxLow = 1 << 5, + psrTxHigh = 1 << 6, + psrTxInProg = 1 << 7 +}; + +/* Bit definitions of the SDMA Config Reg */ +enum sdcr_bits { + sdcrRCMask = 0xf << 2, + sdcrRCBit = 2, + sdcrBLMR = 1 << 6, + sdcrBLMT = 1 << 7, + sdcrPOVR = 1 << 8, + sdcrRIFB = 1 << 9, + sdcrBSZMask = 0x3 << 12, + sdcrBSZBit = 12 +}; + +/* Bit definitions of the SDMA Command Reg */ +enum sdcmr_bits { + sdcmrERD = 1 << 7, + sdcmrAR = 1 << 15, + sdcmrSTDH = 1 << 16, + sdcmrSTDL = 1 << 17, + sdcmrTXDH = 1 << 23, + sdcmrTXDL = 1 << 24, + sdcmrAT = 1 << 31 +}; + +/* Bit definitions of the Interrupt Cause Reg */ +enum icr_bits { + icrRxBuffer = 1, + icrTxBufferHigh = 1 << 2, + icrTxBufferLow = 1 << 3, + icrTxEndHigh = 1 << 6, + icrTxEndLow = 1 << 7, + icrRxError = 1 << 8, + icrTxErrorHigh = 1 << 10, + icrTxErrorLow = 1 << 11, + icrRxOVR = 1 << 12, + icrTxUdr = 1 << 13, + icrRxBufferQ0 = 1 << 16, + icrRxBufferQ1 = 1 << 17, + icrRxBufferQ2 = 1 << 18, + icrRxBufferQ3 = 1 << 19, + icrRxErrorQ0 = 1 << 20, + icrRxErrorQ1 = 1 << 21, + icrRxErrorQ2 = 1 << 22, + icrRxErrorQ3 = 1 << 23, + icrMIIPhySTC = 1 << 28, + icrSMIdone = 1 << 29, + icrEtherIntSum = 1 << 31 +}; + + +/* The Rx and Tx descriptor lists. */ + +typedef struct { + u32 cmdstat; + u32 byte_cnt; + u32 buff_ptr; + u32 next; +} gt96100_td_t; + +#define tdByteCntBit 16 + +typedef struct { + u32 cmdstat; + u32 buff_cnt_sz; + u32 buff_ptr; + u32 next; +} gt96100_rd_t; + +#define rdBuffSzBit 16 +#define rdByteCntMask 0xffff + + +/* Values for the Tx command-status descriptor entry. */ +enum td_cmdstat { + txOwn = 1 << 31, + txAutoMode = 1 << 30, + txEI = 1 << 23, + txGenCRC = 1 << 22, + txPad = 1 << 18, + txFirst = 1 << 17, + txLast = 1 << 16, + txErrorSummary = 1 << 15, + txReTxCntMask = 0x0f << 10, + txReTxCntBit = 10, + txCollision = 1 << 9, + txReTxLimit = 1 << 8, + txUnderrun = 1 << 6, + txLateCollision = 1 << 5 +}; + +#define TxReTxCntBit 10 + +/* Values for the Rx command-status descriptor entry. */ +enum rd_cmdstat { + rxOwn = 1 << 31, + rxAutoMode = 1 << 30, + rxEI = 1 << 23, + rxFirst = 1 << 17, + rxLast = 1 << 16, + rxErrorSummary = 1 << 15, + rxIGMP = 1 << 14, + rxHashExpired = 1 << 13, + rxMissedFrame = 1 << 12, + rxFrameType = 1 << 11, + rxShortFrame = 1 << 8, + rxMaxFrameLen = 1 << 7, + rxOverrun = 1 << 6, + rxCollision = 1 << 4, + rxCRCError = 1 +}; + +/* Bit fields of a Hash Table Entry */ +enum hash_table_entry { + hteValid = 1, + hteSkip = 2, + hteRD = 4 +}; + +// The MIB counters +typedef struct { + u32 byteReceived; + u32 byteSent; + u32 framesReceived; + u32 framesSent; + u32 totalByteReceived; + u32 totalFramesReceived; + u32 broadcastFramesReceived; + u32 multicastFramesReceived; + u32 cRCError; + u32 oversizeFrames; + u32 fragments; + u32 jabber; + u32 collision; + u32 lateCollision; + u32 frames64; + u32 frames65_127; + u32 frames128_255; + u32 frames256_511; + u32 frames512_1023; + u32 frames1024_MaxSize; + u32 macRxError; + u32 droppedFrames; + u32 outMulticastFrames; + u32 outBroadcastFrames; + u32 undersizeFrames; +} mib_counters_t; + + +struct gt96100_private { + gt96100_rd_t *rx_ring; + gt96100_td_t *tx_ring; + // The Rx and Tx rings must be 16-byte aligned + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + char *hash_table; + // The Hash Table must be 8-byte aligned + dma_addr_t hash_table_dma; + int hash_mode; + + // The Rx buffers must be 8-byte aligned + char *rx_buff[RX_RING_SIZE]; + // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes + // of payload must be 8-byte aligned + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + int rx_next_out; /* The next free ring entry to receive */ + int tx_next_in; /* The next free ring entry to send */ + int tx_next_out; /* The last ring entry the ISR processed */ + int tx_count; /* current # of pkts waiting to be sent in Tx ring */ + + mib_counters_t mib; + struct net_device_stats stats; + + int io_size; + int port_num; // 0 or 1 + u32 port_offset; + + int phy_addr; // PHY address + u32 last_psr; // last value of the port status register + + int options; /* User-settable misc. driver options. */ + int drv_flags; + unsigned char phys[2]; /* MII device addresses. */ + spinlock_t lock; /* Serialise access to device */ +}; + +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c --- v2.4.3/linux/drivers/net/hamachi.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/hamachi.c Thu Apr 12 12:15:25 2001 @@ -44,7 +44,7 @@ #define hamachi_debug debug /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 40; -static int mtu = 0; +static int mtu; /* Default values selected by testing on a dual processor PIII-450 */ /* These six interrupt control parameters may be set directly when loading the * module, or through the rx_params and tx_params variables @@ -60,13 +60,13 @@ -Setting to > 1518 causes all frames to be copied -Setting to 0 disables copies */ -static int rx_copybreak = 0; +static int rx_copybreak; /* An override for the hardware detection of bus width. Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. Add 2 to disable parity detection. */ -static int force32 = 0; +static int force32; /* Used to pass the media type, etc. @@ -548,13 +548,13 @@ static int __init hamachi_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - static int did_version = 0; /* Already printed version info. */ + static int did_version; /* Already printed version info. */ struct hamachi_private *hmp; int option, i, rx_int_var, tx_int_var, boguscnt; int chip_id = ent->driver_data; int irq; long ioaddr; - static int card_idx = 0; + static int card_idx; struct net_device *dev; if (hamachi_debug > 0 && did_version++ == 0) diff -u --recursive --new-file v2.4.3/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c --- v2.4.3/linux/drivers/net/hamradio/6pack.c Thu Feb 8 16:32:44 2001 +++ linux/drivers/net/hamradio/6pack.c Fri Apr 13 20:15:55 2001 @@ -711,10 +711,6 @@ /* Do sanity checks on maximum device parameter. */ if (sixpack_maxdev < 4) sixpack_maxdev = 4; - if (sixpack_maxdev * sizeof(void*) >= KMALLOC_MAXSIZE) { - printk(msg_invparm); - return -ENFILE; - } printk(msg_banner, sixpack_maxdev); diff -u --recursive --new-file v2.4.3/linux/drivers/net/hplance.c linux/drivers/net/hplance.c --- v2.4.3/linux/drivers/net/hplance.c Tue Feb 13 13:15:04 2001 +++ linux/drivers/net/hplance.c Thu Apr 12 12:15:25 2001 @@ -63,7 +63,7 @@ static unsigned short hplance_readrdp(struct hplance_private *lp); #ifdef MODULE -static struct hplance_private *root_hplance_dev = NULL; +static struct hplance_private *root_hplance_dev; #endif /* Find all the HP Lance boards and initialise them... */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v2.4.3/linux/drivers/net/hydra.c Tue Feb 13 13:15:04 2001 +++ linux/drivers/net/hydra.c Thu Apr 12 12:15:25 2001 @@ -60,7 +60,7 @@ #define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) #ifdef MODULE -static struct net_device *root_hydra_dev = NULL; +static struct net_device *root_hydra_dev; #endif static int __init hydra_probe(void); diff -u --recursive --new-file v2.4.3/linux/drivers/net/isa-skeleton.c linux/drivers/net/isa-skeleton.c --- v2.4.3/linux/drivers/net/isa-skeleton.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/isa-skeleton.c Thu Apr 12 12:15:25 2001 @@ -163,7 +163,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) { struct net_local *np; - static unsigned version_printed = 0; + static unsigned version_printed; int i; /* diff -u --recursive --new-file v2.4.3/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c --- v2.4.3/linux/drivers/net/jazzsonic.c Sat Mar 3 10:55:47 2001 +++ linux/drivers/net/jazzsonic.c Thu Apr 12 12:15:25 2001 @@ -118,7 +118,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq) { - static unsigned version_printed = 0; + static unsigned version_printed; unsigned int silicon_revision; unsigned int val; struct sonic_local *lp; diff -u --recursive --new-file v2.4.3/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.4.3/linux/drivers/net/lance.c Tue Mar 6 19:28:35 2001 +++ linux/drivers/net/lance.c Thu Apr 12 12:15:25 2001 @@ -389,9 +389,9 @@ int i, reset_val, lance_version; const char *chipname; /* Flags for specific chips or boards. */ - unsigned char hpJ2405A = 0; /* HP ISA adaptor */ - int hp_builtin = 0; /* HP on-board ethernet. */ - static int did_version = 0; /* Already printed version info. */ + unsigned char hpJ2405A = 0; /* HP ISA adaptor */ + int hp_builtin = 0; /* HP on-board ethernet. */ + static int did_version; /* Already printed version info. */ unsigned long flags; /* First we look for special cases. diff -u --recursive --new-file v2.4.3/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.4.3/linux/drivers/net/loopback.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/loopback.c Thu Apr 12 12:11:39 2001 @@ -105,7 +105,7 @@ /* Initialize the rest of the LOOPBACK device. */ int __init loopback_init(struct net_device *dev) { - dev->mtu = PAGE_SIZE - LOOPBACK_OVERHEAD; + dev->mtu = (16 * 1024) + 20 + 20 + 12; dev->hard_start_xmit = loopback_xmit; dev->hard_header = eth_header; dev->hard_header_cache = eth_header_cache; @@ -116,14 +116,12 @@ dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ dev->rebuild_header = eth_rebuild_header; dev->flags = IFF_LOOPBACK; + dev->features = NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA; dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; - - if (num_physpages >= ((128*1024*1024)>>PAGE_SHIFT)) - dev->mtu = 4096*4 - LOOPBACK_OVERHEAD; /* * Fill in the generic fields of the device structure. diff -u --recursive --new-file v2.4.3/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.4.3/linux/drivers/net/mace.c Tue Mar 20 12:05:01 2001 +++ linux/drivers/net/mace.c Thu Apr 12 12:15:25 2001 @@ -20,7 +20,7 @@ #include <asm/pgtable.h> #include "mace.h" -static struct net_device *mace_devs = NULL; +static struct net_device *mace_devs; #define N_RX_RING 8 #define N_TX_RING 6 diff -u --recursive --new-file v2.4.3/linux/drivers/net/macmace.c linux/drivers/net/macmace.c --- v2.4.3/linux/drivers/net/macmace.c Sat Mar 3 10:55:47 2001 +++ linux/drivers/net/macmace.c Thu Apr 12 12:15:25 2001 @@ -200,7 +200,7 @@ int mace68k_probe(struct net_device *unused) { int j; - static int once=0; + static int once; struct mace68k_data *mp; unsigned char *addr; struct net_device *dev; diff -u --recursive --new-file v2.4.3/linux/drivers/net/mvme147.c linux/drivers/net/mvme147.c --- v2.4.3/linux/drivers/net/mvme147.c Tue Feb 13 13:15:04 2001 +++ linux/drivers/net/mvme147.c Thu Apr 12 12:15:25 2001 @@ -66,13 +66,13 @@ typedef unsigned short (*readrdp_t)(void *); #ifdef MODULE -static struct m147lance_private *root_m147lance_dev = NULL; +static struct m147lance_private *root_m147lance_dev; #endif /* Initialise the one and only on-board 7990 */ int __init mvme147lance_probe(struct net_device *dev) { - static int called = 0; + static int called; static const char name[] = "MVME147 LANCE"; struct m147lance_private *lp; u_long *addr; diff -u --recursive --new-file v2.4.3/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.4.3/linux/drivers/net/myri_sbus.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/myri_sbus.c Thu Apr 12 12:15:25 2001 @@ -89,7 +89,7 @@ #endif #ifdef MODULE -static struct myri_eth *root_myri_dev = NULL; +static struct myri_eth *root_myri_dev; #endif static void myri_reset_off(unsigned long lp, unsigned long cregs) @@ -886,7 +886,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, int num) { - static unsigned version_printed = 0; + static unsigned version_printed; struct myri_eth *mp; unsigned char prop_buf[32]; int i; @@ -1109,7 +1109,7 @@ struct net_device *dev = NULL; struct sbus_bus *bus; struct sbus_dev *sdev = 0; - static int called = 0; + static int called; int cards = 0, v; #ifdef MODULE diff -u --recursive --new-file v2.4.3/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c --- v2.4.3/linux/drivers/net/natsemi.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/natsemi.c Thu Apr 12 12:15:25 2001 @@ -64,14 +64,14 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; -static int mtu = 0; +static int mtu; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). This chip uses a 512 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 100; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver diff -u --recursive --new-file v2.4.3/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.4.3/linux/drivers/net/ne.c Tue Mar 6 19:28:34 2001 +++ linux/drivers/net/ne.c Thu Apr 12 12:15:25 2001 @@ -238,7 +238,7 @@ int start_page, stop_page; int neX000, ctron, copam, bad_card; int reg0, ret; - static unsigned version_printed = 0; + static unsigned version_printed; if (!request_region(ioaddr, NE_IO_EXTENT, dev->name)) return -EBUSY; diff -u --recursive --new-file v2.4.3/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.4.3/linux/drivers/net/net_init.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/net_init.c Thu Apr 12 12:16:35 2001 @@ -171,6 +171,7 @@ return dev; } +#if defined(CONFIG_HIPPI) || defined(CONFIG_TR) || defined(CONFIG_NET_FC) static int __register_netdev(struct net_device *dev) { dev_init_buffers(dev); @@ -181,6 +182,7 @@ } return 0; } +#endif /** * init_etherdev - Register ethernet device diff -u --recursive --new-file v2.4.3/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c --- v2.4.3/linux/drivers/net/ni5010.c Tue Mar 6 19:28:34 2001 +++ linux/drivers/net/ni5010.c Thu Apr 12 12:15:25 2001 @@ -74,7 +74,7 @@ "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n"; /* bufsize_rcv == 0 means autoprobing */ -static unsigned int bufsize_rcv = 0; +static unsigned int bufsize_rcv; #define jumpered_interrupts /* IRQ line jumpered on board */ #undef jumpered_dma /* No DMA used */ @@ -186,7 +186,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) { - static unsigned version_printed = 0; + static unsigned version_printed; int i; unsigned int data = 0; int boguscount = 40; diff -u --recursive --new-file v2.4.3/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.4.3/linux/drivers/net/ni52.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/ni52.c Thu Apr 12 12:15:25 2001 @@ -99,9 +99,9 @@ * < 30.Sep.93: first versions */ -static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */ -static int automatic_resume = 0; /* experimental .. better should be zero */ -static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */ +static int debuglevel; /* debug-printk 0: off 1: a few 2: more */ +static int automatic_resume; /* experimental .. better should be zero */ +static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */ static int fifo=0x8; /* don't change */ /* #define REALLY_SLOW_IO */ @@ -1289,8 +1289,8 @@ /* set: io,irq,memstart,memend or set it when calling insmod */ static int irq=9; static int io=0x300; -static long memstart=0; /* e.g 0xd0000 */ -static long memend=0; /* e.g 0xd4000 */ +static long memstart; /* e.g 0xd0000 */ +static long memend; /* e.g 0xd4000 */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); diff -u --recursive --new-file v2.4.3/linux/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c --- v2.4.3/linux/drivers/net/pci-skeleton.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/pci-skeleton.c Thu Apr 12 12:15:25 2001 @@ -36,7 +36,7 @@ -----<snip>----- This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + of the GNU General Public License, incorporated herein by reference. ----------------------------------------------------------------------------- @@ -740,7 +740,7 @@ int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - static int printed_version = 0; + static int printed_version; u8 tmp; DPRINTK ("ENTER\n"); diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c --- v2.4.3/linux/drivers/net/pcmcia/aironet4500_cs.c Tue Mar 20 12:05:00 2001 +++ linux/drivers/net/pcmcia/aironet4500_cs.c Fri Apr 13 20:26:07 2001 @@ -179,12 +179,14 @@ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); if (!link) return NULL; + memset(link, 0, sizeof(struct dev_link_t)); + link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); if (!link->dev) { kfree(link); return NULL; } - memset(link, 0, sizeof(struct dev_link_t)); + memset(link->dev, 0, sizeof(struct dev_node_t)); link->release.function = &awc_release; diff -u --recursive --new-file v2.4.3/linux/drivers/net/pcmcia/hermes.c linux/drivers/net/pcmcia/hermes.c --- v2.4.3/linux/drivers/net/pcmcia/hermes.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/pcmcia/hermes.c Thu Apr 12 12:16:35 2001 @@ -19,7 +19,6 @@ static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>"; -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/smp.h> diff -u --recursive --new-file v2.4.3/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.4.3/linux/drivers/net/plip.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/plip.c Thu Apr 12 12:15:25 2001 @@ -1293,7 +1293,7 @@ } static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 }; -static int timid = 0; +static int timid; MODULE_PARM(parport, "1-" __MODULE_STRING(PLIP_MAX) "i"); MODULE_PARM(timid, "1i"); @@ -1314,7 +1314,7 @@ * available to use. */ static void plip_attach (struct parport *port) { - static int i = 0; + static int i; if ((parport[0] == -1 && (!timid || !port->devices)) || plip_searchfor(parport, port->number)) { @@ -1377,7 +1377,7 @@ #ifndef MODULE -static int parport_ptr = 0; +static int parport_ptr; static int __init plip_setup(char *str) { diff -u --recursive --new-file v2.4.3/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c --- v2.4.3/linux/drivers/net/ptifddi.c Tue Jul 11 15:46:08 2000 +++ linux/drivers/net/ptifddi.c Thu Apr 12 12:15:25 2001 @@ -16,7 +16,7 @@ #include "ptifddi_asm.h" #ifdef MODULE -static struct ptifddi *root_pti_dev = NULL; +static struct ptifddi *root_pti_dev; #endif static inline void pti_reset(struct ptifddi *pp) @@ -151,7 +151,7 @@ static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, int num) { - static unsigned version_printed = 0; + static unsigned version_printed; struct ptifddi *pp; int i; @@ -208,7 +208,7 @@ { struct sbus_bus *bus; struct sbus_dev *sdev = 0; - static int called = 0; + static int called; int cards = 0, v; if(called) diff -u --recursive --new-file v2.4.3/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c --- v2.4.3/linux/drivers/net/rcpci45.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/rcpci45.c Thu Apr 12 12:15:25 2001 @@ -91,7 +91,7 @@ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 -static U32 DriverControlWord = 0; +static U32 DriverControlWord; static void rc_timer(unsigned long); diff -u --recursive --new-file v2.4.3/linux/drivers/net/saa9730.c linux/drivers/net/saa9730.c --- v2.4.3/linux/drivers/net/saa9730.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/saa9730.c Fri Apr 13 20:26:07 2001 @@ -0,0 +1,1082 @@ +/* + * 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. + * + * ######################################################################## + * + * SAA9730 ethernet driver. + * + */ + +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/pci.h> + +#include <asm/addrspace.h> +#include <asm/mips-boards/prom.h> + +#include "saa9730.h" + +#ifdef LAN_SAA9730_DEBUG +int lan_saa9730_debug = LAN_SAA9730_DEBUG; +#else +int lan_saa9730_debug; +#endif + + +/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ +static unsigned int pci_irq_line = 0; + +#define INL(a) inl((unsigned long)a) +#define OUTL(x,a) outl(x,(unsigned long)a) + +static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); + OUTL(INL(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptStatus1); + OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT | + EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1); +} +static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); + OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptEnable1); +} + +static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1); +} + +static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); +} + +static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) +{ + OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, + &lp->evm_saa9730_regs->InterruptBlock1); +} + +static void show_saa9730_regs(struct lan_saa9730_private *lp) +{ + int i, j; + printk("TxmBufferA = %x\n", lp->TxmBuffer[0][0]); + printk("TxmBufferB = %x\n", lp->TxmBuffer[1][0]); + printk("RcvBufferA = %x\n", lp->RcvBuffer[0][0]); + printk("RcvBufferB = %x\n", lp->RcvBuffer[1][0]); + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { + printk("TxmBuffer[%d][%d] = %x\n", i, j, + le32_to_cpu(*(unsigned int *) + lp->TxmBuffer[i][j])); + } + } + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { + printk("RcvBuffer[%d][%d] = %x\n", i, j, + le32_to_cpu(*(unsigned int *) + lp->RcvBuffer[i][j])); + } + } + printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n", + INL(&lp->evm_saa9730_regs->InterruptBlock1)); + printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n", + INL(&lp->evm_saa9730_regs->InterruptStatus1)); + printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n", + INL(&lp->evm_saa9730_regs->InterruptEnable1)); + printk("lp->lan_saa9730_regs->Ok2Use = %x\n", + INL(&lp->lan_saa9730_regs->Ok2Use)); + printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex); + printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex); + printk("lp->PendingTxmBufferIndex = %x\n", + lp->PendingTxmBufferIndex); + printk("lp->PendingTxmPacketIndex = %x\n", + lp->PendingTxmPacketIndex); + printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n", + INL(&lp->lan_saa9730_regs->LanDmaCtl)); + printk("lp->lan_saa9730_regs->DmaStatus = %x\n", + INL(&lp->lan_saa9730_regs->DmaStatus)); + printk("lp->lan_saa9730_regs->CamCtl = %x\n", + INL(&lp->lan_saa9730_regs->CamCtl)); + printk("lp->lan_saa9730_regs->TxCtl = %x\n", + INL(&lp->lan_saa9730_regs->TxCtl)); + printk("lp->lan_saa9730_regs->TxStatus = %x\n", + INL(&lp->lan_saa9730_regs->TxStatus)); + printk("lp->lan_saa9730_regs->RxCtl = %x\n", + INL(&lp->lan_saa9730_regs->RxCtl)); + printk("lp->lan_saa9730_regs->RxStatus = %x\n", + INL(&lp->lan_saa9730_regs->RxStatus)); + for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { + OUTL(i, &lp->lan_saa9730_regs->CamAddress); + printk("lp->lan_saa9730_regs->CamData = %x\n", + INL(&lp->lan_saa9730_regs->CamData)); + } + printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets); + printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors); + printk("lp->stats.tx_aborted_errors = %lx\n", + lp->stats.tx_aborted_errors); + printk("lp->stats.tx_window_errors = %lx\n", + lp->stats.tx_window_errors); + printk("lp->stats.tx_carrier_errors = %lx\n", + lp->stats.tx_carrier_errors); + printk("lp->stats.tx_fifo_errors = %lx\n", + lp->stats.tx_fifo_errors); + printk("lp->stats.tx_heartbeat_errors = %lx\n", + lp->stats.tx_heartbeat_errors); + printk("lp->stats.collisions = %lx\n", lp->stats.collisions); + + printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets); + printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors); + printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped); + printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors); + printk("lp->stats.rx_frame_errors = %lx\n", + lp->stats.rx_frame_errors); + printk("lp->stats.rx_fifo_errors = %lx\n", + lp->stats.rx_fifo_errors); + printk("lp->stats.rx_length_errors = %lx\n", + lp->stats.rx_length_errors); + + printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n", + INL(&lp->lan_saa9730_regs->DebugPCIMasterAddr)); + printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanTxStateMachine)); + printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanRxStateMachine)); + printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanTxFifoPointers)); + printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanRxFifoPointers)); + printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n", + INL(&lp->lan_saa9730_regs->DebugLanCtlStateMachine)); +} + +static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp) +{ + int i, j; + + /* Init RX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { + *(unsigned int *) lp->RcvBuffer[i][j] = + cpu_to_le32(RXSF_READY << + RX_STAT_CTL_OWNER_SHF); + } + } + + /* Init TX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { + *(unsigned int *) lp->TxmBuffer[i][j] = + cpu_to_le32(TXSF_EMPTY << + TX_STAT_CTL_OWNER_SHF); + } + } +} + +static int lan_saa9730_allocate_buffers(struct lan_saa9730_private *lp) +{ + unsigned int mem_size; + void *Pa; + unsigned int i, j, RcvBufferSize, TxmBufferSize; + unsigned int buffer_start; + + /* + * Allocate all RX and TX packets in one chunk. + * The Rx and Tx packets must be PACKET_SIZE aligned. + */ + mem_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) * + LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) + + LAN_SAA9730_PACKET_SIZE; + buffer_start = + (unsigned int) kmalloc(mem_size, GFP_DMA | GFP_KERNEL); + + /* + * Set DMA buffer to kseg1 (uncached). + * Make sure to flush before using it uncached. + */ + Pa = (void *) KSEG1ADDR((buffer_start + LAN_SAA9730_PACKET_SIZE) & + ~(LAN_SAA9730_PACKET_SIZE - 1)); + dma_cache_wback_inv((unsigned long) Pa, mem_size); + + /* Initialize buffer space */ + RcvBufferSize = LAN_SAA9730_PACKET_SIZE; + TxmBufferSize = LAN_SAA9730_PACKET_SIZE; + lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE; + lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE; + + /* Init RX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { + *(unsigned int *) Pa = + cpu_to_le32(RXSF_READY << + RX_STAT_CTL_OWNER_SHF); + lp->RcvBuffer[i][j] = (unsigned int) Pa; + Pa += RcvBufferSize; + } + } + + /* Init TX buffers */ + for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { + for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { + *(unsigned int *) Pa = + cpu_to_le32(TXSF_EMPTY << + TX_STAT_CTL_OWNER_SHF); + lp->TxmBuffer[i][j] = (unsigned int) Pa; + Pa += TxmBufferSize; + } + } + + /* + * Set rx buffer A and rx buffer B to point to the first two buffer + * spaces. + */ + OUTL(PHYSADDR(lp->RcvBuffer[0][0]), + &lp->lan_saa9730_regs->RxBuffA); + OUTL(PHYSADDR(lp->RcvBuffer[1][0]), + &lp->lan_saa9730_regs->RxBuffB); + + /* Initialize Buffer Index */ + lp->NextRcvPacketIndex = 0; + lp->NextRcvToUseIsA = 1; + + /* Set current buffer index & next availble packet index */ + lp->NextTxmPacketIndex = 0; + lp->NextTxmBufferIndex = 0; + lp->PendingTxmPacketIndex = 0; + lp->PendingTxmBufferIndex = 0; + + /* + * Set txm_buf_a and txm_buf_b to point to the first two buffer + * space + */ + OUTL(PHYSADDR(lp->TxmBuffer[0][0]), + &lp->lan_saa9730_regs->TxBuffA); + OUTL(PHYSADDR(lp->TxmBuffer[1][0]), + &lp->lan_saa9730_regs->TxBuffB); + + /* Set packet number */ + OUTL((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) | + (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) | + (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) | + (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF), + &lp->lan_saa9730_regs->PacketCount); + + return 0; +} + +static int lan_saa9730_cam_load(struct lan_saa9730_private *lp) +{ + unsigned int i; + unsigned char *NetworkAddress; + + NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0]; + + for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { + /* First set address to where data is written */ + OUTL(i, &lp->lan_saa9730_regs->CamAddress); + OUTL((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16) + | (NetworkAddress[2] << 8) | NetworkAddress[3], + &lp->lan_saa9730_regs->CamData); + NetworkAddress += 4; + } + return 0; +} + +static int lan_saa9730_cam_init(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + unsigned int i; + + /* Copy MAC-address into all entries. */ + for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) { + memcpy((unsigned char *) lp->PhysicalAddress[i], + (unsigned char *) dev->dev_addr, 6); + } + + return 0; +} + +static int lan_saa9730_mii_init(struct lan_saa9730_private *lp) +{ + int i, l; + + /* Check link status, spin here till station is not busy. */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { + i++; + if (i > 100) { + printk("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* Now set the control and address register. */ + OUTL(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF, + &lp->lan_saa9730_regs->StationMgmtCtl); + + /* check link status, spin here till station is not busy */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { + i++; + if (i > 100) { + printk("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* Wait for 1 ms. */ + udelay(1000); + + /* Check the link status. */ + if (INL(&lp->lan_saa9730_regs->StationMgmtData) & + PHY_STATUS_LINK_UP) { + /* Link is up. */ + return 0; + } else { + /* Link is down, reset the PHY first. */ + + /* set PHY address = 'CONTROL' */ + OUTL(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, + &lp->lan_saa9730_regs->StationMgmtCtl); + + /* Wait for 1 ms. */ + udelay(1000); + + /* set 'CONTROL' = force reset and renegotiate */ + OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG | + PHY_CONTROL_RESTART_AUTO_NEG, + &lp->lan_saa9730_regs->StationMgmtData); + + /* Wait for 50 ms. */ + udelay(50 * 1000); + + /* set 'BUSY' to start operation */ + OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | + PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); + + /* await completion */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & + MD_CA_BUSY) { + i++; + if (i > 100) { + printk + ("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* Wait for 1 ms. */ + udelay(1000); + + for (l = 0; l < 2; l++) { + /* set PHY address = 'STATUS' */ + OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | + PHY_STATUS, + &lp->lan_saa9730_regs->StationMgmtCtl); + + /* await completion */ + i = 0; + while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & + MD_CA_BUSY) { + i++; + if (i > 100) { + printk + ("Error: lan_saa9730_mii_init: timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + /* wait for 3 sec. */ + udelay(3000 * 1000); + + /* check the link status */ + if (INL(&lp->lan_saa9730_regs->StationMgmtData) & + PHY_STATUS_LINK_UP) { + /* link is up */ + break; + } + } + } + + return 0; +} + +static int lan_saa9730_control_init(struct lan_saa9730_private *lp) +{ + /* Initialize DMA control register. */ + OUTL((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) | + (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) | + (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF) + | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN | + DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN, + &lp->lan_saa9730_regs->LanDmaCtl); + + /* Initial MAC control register. */ + OUTL((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP, + &lp->lan_saa9730_regs->MacCtl); + + /* Initialize CAM control register. */ + OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC, + &lp->lan_saa9730_regs->CamCtl); + + /* + * Initialize CAM enable register, only turn on first entry, should + * contain own addr. + */ + OUTL(0x0001, &lp->lan_saa9730_regs->CamEnable); + + /* Initialize Tx control register */ + OUTL(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl); + + /* Initialize Rcv control register */ + OUTL(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl); + + /* Reset DMA engine */ + OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); + + return 0; +} + +static int lan_saa9730_stop(struct lan_saa9730_private *lp) +{ + int i; + + /* Stop DMA first */ + OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) & + ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA), + &lp->lan_saa9730_regs->LanDmaCtl); + + /* Set the SW Reset bits in DMA and MAC control registers */ + OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); + OUTL(INL(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET, + &lp->lan_saa9730_regs->MacCtl); + + /* + * Wait for MAC reset to have finished. The reset bit is auto cleared + * when the reset is done. + */ + i = 0; + while (INL(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) { + i++; + if (i > 100) { + printk + ("Error: lan_sa9730_stop: MAC reset timeout\n"); + return -1; + } + udelay(1000); /* wait 1 ms. */ + } + + return 0; +} + +static int lan_saa9730_dma_init(struct lan_saa9730_private *lp) +{ + /* Stop lan controller. */ + lan_saa9730_stop(lp); + + OUTL(LAN_SAA9730_DEFAULT_TIME_OUT_CNT, + &lp->lan_saa9730_regs->Timeout); + + return 0; +} + +static int lan_saa9730_start(struct lan_saa9730_private *lp) +{ + lan_saa9730_buffer_init(lp); + + /* Initialize Rx Buffer Index */ + lp->NextRcvPacketIndex = 0; + lp->NextRcvToUseIsA = 1; + + /* Set current buffer index & next availble packet index */ + lp->NextTxmPacketIndex = 0; + lp->NextTxmBufferIndex = 0; + lp->PendingTxmPacketIndex = 0; + lp->PendingTxmBufferIndex = 0; + + OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA | + DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl); + + /* For Tx, turn on MAC then DMA */ + OUTL(INL(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN, + &lp->lan_saa9730_regs->TxCtl); + + /* For Rx, turn on DMA then MAC */ + OUTL(INL(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN, + &lp->lan_saa9730_regs->RxCtl); + + /* Set Ok2Use to let hardware owns the buffers */ + OUTL(OK2USE_RX_A | OK2USE_RX_B | OK2USE_TX_A | OK2USE_TX_B, + &lp->lan_saa9730_regs->Ok2Use); + + return 0; +} + +static int lan_saa9730_restart(struct lan_saa9730_private *lp) +{ + lan_saa9730_stop(lp); + lan_saa9730_start(lp); + + return 0; +} + +static int lan_saa9730_tx(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + unsigned int *pPacket; + unsigned int tx_status; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_tx interrupt\n"); + + /* Clear interrupt. */ + OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); + + while (1) { + pPacket = + (unsigned int *) lp->TxmBuffer[lp-> + PendingTxmBufferIndex] + [lp->PendingTxmPacketIndex]; + + /* Get status of first packet transmitted. */ + tx_status = le32_to_cpu(*pPacket); + + /* Check ownership. */ + if ((tx_status & TX_STAT_CTL_OWNER_MSK) != + (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; + + /* Check for error. */ + if (tx_status & TX_STAT_CTL_ERROR_MSK) { + if (lan_saa9730_debug > 1) + printk("lan_saa9730_tx: tx error = %x\n", + tx_status); + + lp->stats.tx_errors++; + if (tx_status & + (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_aborted_errors++; + if (tx_status & + (TX_STATUS_LATE_COLL << + TX_STAT_CTL_STATUS_SHF)) lp->stats. + tx_window_errors++; + if (tx_status & + (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_carrier_errors++; + if (tx_status & + (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_fifo_errors++; + if (tx_status & + (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) + lp->stats.tx_heartbeat_errors++; + + lp->stats.collisions += + tx_status & TX_STATUS_TX_COLL_MSK; + } + + /* Free buffer. */ + *pPacket = + cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); + + /* Update pending index pointer. */ + lp->PendingTxmPacketIndex++; + if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { + lp->PendingTxmPacketIndex = 0; + lp->PendingTxmBufferIndex ^= 1; + } + } + + /* Make sure A and B are available to hardware. */ + OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use); + + if (netif_queue_stopped(dev)) { + /* The tx buffer is no longer full. */ + netif_wake_queue(dev); + } + + return 0; +} + +static int lan_saa9730_rx(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + int len = 0; + struct sk_buff *skb = 0; + unsigned int rx_status; + int BufferIndex; + int PacketIndex; + unsigned int *pPacket; + unsigned char *pData; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_rx interrupt\n"); + + /* Clear receive interrupts. */ + OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | + DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); + + /* Address next packet */ + if (lp->NextRcvToUseIsA) + BufferIndex = 0; + else + BufferIndex = 1; + PacketIndex = lp->NextRcvPacketIndex; + pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex]; + rx_status = le32_to_cpu(*pPacket); + + /* Process each packet. */ + while ((rx_status & RX_STAT_CTL_OWNER_MSK) == + (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { + /* Check the rx status. */ + if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { + /* Received packet is good. */ + len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> + RX_STAT_CTL_LENGTH_SHF; + + pData = (unsigned char *) pPacket; + pData += 4; + skb = dev_alloc_skb(len + 2); + if (skb == 0) { + printk + ("%s: Memory squeeze, deferring packet.\n", + dev->name); + lp->stats.rx_dropped++; + } else { + lp->stats.rx_bytes += len; + lp->stats.rx_packets++; + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align */ + skb_put(skb, len); /* make room */ + eth_copy_and_sum(skb, + (unsigned char *) pData, + len, 0); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + } + } else { + /* We got an error packet. */ + if (lan_saa9730_debug > 2) + printk + ("lan_saa9730_rx: We got an error packet = %x\n", + rx_status); + + lp->stats.rx_errors++; + if (rx_status & + (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) + lp->stats.rx_crc_errors++; + if (rx_status & + (RX_STATUS_ALIGN_ERR << + RX_STAT_CTL_STATUS_SHF)) lp->stats. + rx_frame_errors++; + if (rx_status & + (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) + lp->stats.rx_fifo_errors++; + if (rx_status & + (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) + lp->stats.rx_length_errors++; + } + + /* Indicate we have processed the buffer. */ + *pPacket = + cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); + + /* Go to next packet in sequence. */ + lp->NextRcvPacketIndex++; + if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { + lp->NextRcvPacketIndex = 0; + if (BufferIndex) { + lp->NextRcvToUseIsA = 1; + } else { + lp->NextRcvToUseIsA = 0; + } + } + OUTL(OK2USE_RX_A | OK2USE_RX_B, + &lp->lan_saa9730_regs->Ok2Use); + + /* Address next packet */ + if (lp->NextRcvToUseIsA) + BufferIndex = 0; + else + BufferIndex = 1; + PacketIndex = lp->NextRcvPacketIndex; + pPacket = + (unsigned int *) lp-> + RcvBuffer[BufferIndex][PacketIndex]; + rx_status = le32_to_cpu(*pPacket); + } + + /* Make sure A and B are available to hardware. */ + OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); + + return 0; +} + +static void lan_saa9730_interrupt(const int irq, void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_interrupt\n"); + + /* Disable the EVM LAN interrupt. */ + evm_saa9730_block_lan_int(lp); + + /* Clear the EVM LAN interrupt. */ + evm_saa9730_clear_lan_int(lp); + + /* Service pending transmit interrupts. */ + if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) + lan_saa9730_tx(dev); + + /* Service pending receive interrupts. */ + if (INL(&lp->lan_saa9730_regs->DmaStatus) & + (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | + DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); + + /* Enable the EVM LAN interrupt. */ + evm_saa9730_unblock_lan_int(lp); + + return; +} + +static int lan_saa9730_open_fail(struct net_device *dev) +{ + return -ENODEV; +} + +static int lan_saa9730_open(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + /* Associate IRQ with lan_saa9730_interrupt */ + if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", + dev)) { + printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + /* Enable the Lan interrupt in the event manager. */ + evm_saa9730_enable_lan_int(lp); + + /* Start the LAN controller */ + if (lan_saa9730_start(lp)) + return -1; + + netif_start_queue(dev); + + return 0; +} + +static int lan_saa9730_write(struct lan_saa9730_private *lp, + struct sk_buff *skb, int skblen) +{ + unsigned char *pbData = skb->data; + unsigned int len = skblen; + unsigned char *pbPacketData; + unsigned int tx_status; + int BufferIndex; + int PacketIndex; + + if (lan_saa9730_debug > 5) + printk("lan_saa9730_write: skb=%08x\n", + (unsigned int) skb); + + BufferIndex = lp->NextTxmBufferIndex; + PacketIndex = lp->NextTxmPacketIndex; + + tx_status = + le32_to_cpu(*(unsigned int *) lp-> + TxmBuffer[BufferIndex][PacketIndex]); + if ((tx_status & TX_STAT_CTL_OWNER_MSK) != + (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { + if (lan_saa9730_debug > 4) + printk + ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", + tx_status); + return -1; + } + + lp->NextTxmPacketIndex++; + if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { + lp->NextTxmPacketIndex = 0; + lp->NextTxmBufferIndex ^= 1; + } + + pbPacketData = + (unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex]; + pbPacketData += 4; + + /* copy the bits */ + memcpy(pbPacketData, pbData, len); + + /* Set transmit status for hardware */ + *(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] = + cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | + (TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF) + | (len << TX_STAT_CTL_LENGTH_SHF)); + + /* Set hardware tx buffer. */ + OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use); + + return 0; +} + +static void lan_saa9730_tx_timeout(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + /* Transmitter timeout, serious problems */ + lp->stats.tx_errors++; + printk("%s: transmit timed out, reset\n", dev->name); + /*show_saa9730_regs(lp); */ + lan_saa9730_restart(lp); + + dev->trans_start = jiffies; + netif_start_queue(dev); +} + +static int lan_saa9730_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + unsigned long flags; + int skblen; + int len; + + if (lan_saa9730_debug > 4) + printk("Send packet: skb=%08x\n", (unsigned int) skb); + + skblen = skb->len; + save_and_cli(flags); + len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; + + if (lan_saa9730_write(lp, skb, skblen)) { + restore_flags(flags); + printk + ("Error when writing packet to controller: skb=%08x\n", + (unsigned int) skb); + netif_stop_queue(dev); + return -1; + } + + lp->stats.tx_bytes += len; + lp->stats.tx_packets++; + + dev->trans_start = jiffies; + netif_start_queue(dev); + dev_kfree_skb(skb); + + restore_flags(flags); + + return 0; +} + +static int lan_saa9730_close(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + if (lan_saa9730_debug > 1) + printk("lan_saa9730_close:\n"); + + netif_stop_queue(dev); + + /* Disable the Lan interrupt in the event manager. */ + evm_saa9730_disable_lan_int(lp); + + /* Stop the controller */ + if (lan_saa9730_stop(lp)) + return -1; + + free_irq(dev->irq, (void *) dev); + + return 0; +} + +static struct net_device_stats *lan_saa9730_get_stats(struct net_device + *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + return &lp->stats; +} + +static void lan_saa9730_set_multicast(struct net_device *dev) +{ + struct lan_saa9730_private *lp = + (struct lan_saa9730_private *) dev->priv; + + /* Stop the controller */ + lan_saa9730_stop(lp); + + if (dev->flags & IFF_PROMISC) { + /* accept all packets */ + OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | + CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, + &lp->lan_saa9730_regs->CamCtl); + } else { + if (dev->flags & IFF_ALLMULTI) { + /* accept all multicast packets */ + OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | + CAM_CONTROL_BROAD_ACC, + &lp->lan_saa9730_regs->CamCtl); + } else { + /* + * Will handle the multicast stuff later. -carstenl + */ + } + } + + lan_saa9730_restart(lp); +} + +static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq) +{ + struct lan_saa9730_private *lp; + unsigned char ethernet_addr[6]; + + dev = init_etherdev(dev, 0); + + dev->open = lan_saa9730_open_fail; + if (get_ethernet_addr(ethernet_addr)) + return -1; + + memcpy(dev->dev_addr, ethernet_addr, 6); + dev->base_addr = ioaddr; + dev->irq = irq; + + /* + * Make certain the data structures used by the controller are aligned + * and DMAble. + */ + lp = (struct lan_saa9730_private *) (((unsigned long) + kmalloc(sizeof(*lp) + 7, + GFP_DMA | GFP_KERNEL) + + 7) & ~7); + + dev->priv = lp; + memset(lp, 0, sizeof(*lp)); + + /* Set SAA9730 LAN base address. */ + lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr + + SAA9730_LAN_REGS_ADDR); + + /* Set SAA9730 EVM base address. */ + lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr + + SAA9730_EVM_REGS_ADDR); + + /* Allocate LAN RX/TX frame buffer space. */ + if (lan_saa9730_allocate_buffers(lp)) + return -1; + + /* Stop LAN controller. */ + if (lan_saa9730_stop(lp)) + return -1; + + /* Initialize CAM registers. */ + if (lan_saa9730_cam_init(dev)) + return -1; + + /* Initialize MII registers. */ + if (lan_saa9730_mii_init(lp)) + return -1; + + /* Initialize control registers. */ + if (lan_saa9730_control_init(lp)) + return -1; + + /* Load CAM registers. */ + if (lan_saa9730_cam_load(lp)) + return -1; + + /* Initialize DMA context registers. */ + if (lan_saa9730_dma_init(lp)) + return -1; + + dev->open = lan_saa9730_open; + dev->hard_start_xmit = lan_saa9730_start_xmit; + dev->stop = lan_saa9730_close; + dev->get_stats = lan_saa9730_get_stats; + dev->set_multicast_list = lan_saa9730_set_multicast; + dev->tx_timeout = lan_saa9730_tx_timeout; + dev->watchdog_timeo = (HZ >> 1); + dev->dma = 0; + + return 0; +} + + +static int __init saa9730_probe(void) +{ + struct net_device *dev = NULL; + + if (pci_present()) { + struct pci_dev *pdev = NULL; + if (lan_saa9730_debug > 1) + printk + ("saa9730.c: PCI bios is present, checking for devices...\n"); + + while ((pdev = pci_find_device(PCI_VENDOR_ID_PHILIPS, + PCI_DEVICE_ID_PHILIPS_SAA9730, + pdev))) { + unsigned int pci_ioaddr; + + pci_irq_line = pdev->irq; + /* LAN base address in located at BAR 1. */ + + pci_ioaddr = pci_resource_start(pdev, 1); + pci_set_master(pdev); + + printk("Found SAA9730 (PCI) at %#x, irq %d.\n", + pci_ioaddr, pci_irq_line); + if (!lan_saa9730_init + (dev, pci_ioaddr, pci_irq_line)) return 0; + else + printk("Lan init failed.\n"); + } + } + + return -ENODEV; +} + +module_init(saa9730_probe); diff -u --recursive --new-file v2.4.3/linux/drivers/net/saa9730.h linux/drivers/net/saa9730.h --- v2.4.3/linux/drivers/net/saa9730.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/saa9730.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,370 @@ +/* + * 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. + * + * ######################################################################## + * + * SAA9730 ethernet driver description. + * + */ +#ifndef _SAA9730_H +#define _SAA9730_H + + +/* Number of 6-byte entries in the CAM. */ +#define LAN_SAA9730_CAM_ENTRIES 10 +#define LAN_SAA9730_CAM_DWORDS ((LAN_SAA9730_CAM_ENTRIES*6)/4) + +/* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */ +#define LAN_SAA9730_PACKET_SIZE 2048 + +/* + * Number of TX buffers = number of RX buffers = 2, which is fixed according + * to HW requirements. + */ +#define LAN_SAA9730_BUFFERS 2 + +/* Number of RX packets per RX buffer. */ +#define LAN_SAA9730_RCV_Q_SIZE 15 + +/* Number of TX packets per TX buffer. */ +#define LAN_SAA9730_TXM_Q_SIZE 15 + +/* + * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD + * packets received. + * If however we receive less than LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD + * packets, the hardware can timeout after a certain time and still tell + * us packets have arrived. + * The timeout value in unit of 32 PCI clocks (33Mhz). + * The value 200 approximates 0.0002 seconds. + */ +#define LAN_SAA9730_RCV_Q_INT_THRESHOLD 1 +#define LAN_SAA9730_DEFAULT_TIME_OUT_CNT 10 + +#define RXSF_NDIS 0 +#define RXSF_READY 2 +#define RXSF_HWDONE 3 + +#define TXSF_EMPTY 0 +#define TXSF_READY 2 +#define TXSF_HWDONE 3 + +#define LANEND_LITTLE 0 +#define LANEND_BIG_2143 1 +#define LANEND_BIG_4321 2 + +#define LANMB_ANY 0 +#define LANMB_8 1 +#define LANMB_32 2 +#define LANMB_64 3 + +#define MACCM_AUTOMATIC 0 +#define MACCM_10MB 1 +#define MACCM_MII 2 + +/* + * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board) + */ +#define PHY_CONTROL 0x0 +#define PHY_STATUS 0x1 +#define PHY_STATUS_LINK_UP 0x4 +#define PHY_CONTROL_RESET 0x8000 +#define PHY_CONTROL_AUTO_NEG 0x1000 +#define PHY_CONTROL_RESTART_AUTO_NEG 0x0200 +#define PHY_ADDRESS 0x0 + +/* PK_COUNT register. */ +#define PK_COUNT_TX_A_SHF 24 +#define PK_COUNT_TX_A_MSK (0xff << PK_COUNT_TX_A_SHF) +#define PK_COUNT_TX_B_SHF 16 +#define PK_COUNT_TX_B_MSK (0xff << PK_COUNT_TX_B_SHF) +#define PK_COUNT_RX_A_SHF 8 +#define PK_COUNT_RX_A_MSK (0xff << PK_COUNT_RX_A_SHF) +#define PK_COUNT_RX_B_SHF 0 +#define PK_COUNT_RX_B_MSK (0xff << PK_COUNT_RX_B_SHF) + +/* OK2USE register. */ +#define OK2USE_TX_A 0x8 +#define OK2USE_TX_B 0x4 +#define OK2USE_RX_A 0x2 +#define OK2USE_RX_B 0x1 + +/* LAN DMA CONTROL register. */ +#define DMA_CTL_BLK_INT 0x80000000 +#define DMA_CTL_MAX_XFER_SHF 18 +#define DMA_CTL_MAX_XFER_MSK (0x3 << LAN_DMA_CTL_MAX_XFER_SHF) +#define DMA_CTL_ENDIAN_SHF 16 +#define DMA_CTL_ENDIAN_MSK (0x3 << LAN_DMA_CTL_ENDIAN_SHF) +#define DMA_CTL_RX_INT_COUNT_SHF 8 +#define DMA_CTL_RX_INT_COUNT_MSK (0xff << LAN_DMA_CTL_RX_INT_COUNT_SHF) +#define DMA_CTL_EN_TX_DMA 0x00000080 +#define DMA_CTL_EN_RX_DMA 0x00000040 +#define DMA_CTL_RX_INT_BUFFUL_EN 0x00000020 +#define DMA_CTL_RX_INT_TO_EN 0x00000010 +#define DMA_CTL_RX_INT_EN 0x00000008 +#define DMA_CTL_TX_INT_EN 0x00000004 +#define DMA_CTL_MAC_TX_INT_EN 0x00000002 +#define DMA_CTL_MAC_RX_INT_EN 0x00000001 + +/* DMA STATUS register. */ +#define DMA_STATUS_BAD_ADDR_SHF 16 +#define DMA_STATUS_BAD_ADDR_MSK (0xf << DMA_STATUS_BAD_ADDR_SHF) +#define DMA_STATUS_RX_PKTS_RECEIVED_SHF 8 +#define DMA_STATUS_RX_PKTS_RECEIVED_MSK (0xff << DMA_STATUS_RX_PKTS_RECEIVED_SHF) +#define DMA_STATUS_TX_EN_SYNC 0x00000080 +#define DMA_STATUS_RX_BUF_A_FUL 0x00000040 +#define DMA_STATUS_RX_BUF_B_FUL 0x00000020 +#define DMA_STATUS_RX_TO_INT 0x00000010 +#define DMA_STATUS_RX_INT 0x00000008 +#define DMA_STATUS_TX_INT 0x00000004 +#define DMA_STATUS_MAC_TX_INT 0x00000002 +#define DMA_STATUS_MAC_RX_INT 0x00000001 + +/* DMA TEST/PANIC SWITHES register. */ +#define DMA_TEST_LOOPBACK 0x01000000 +#define DMA_TEST_SW_RESET 0x00000001 + +/* MAC CONTROL register. */ +#define MAC_CONTROL_EN_MISS_ROLL 0x00002000 +#define MAC_CONTROL_MISS_ROLL 0x00000400 +#define MAC_CONTROL_LOOP10 0x00000080 +#define MAC_CONTROL_CONN_SHF 5 +#define MAC_CONTROL_CONN_MSK (0x3 << MAC_CONTROL_CONN_SHF) +#define MAC_CONTROL_MAC_LOOP 0x00000010 +#define MAC_CONTROL_FULL_DUP 0x00000008 +#define MAC_CONTROL_RESET 0x00000004 +#define MAC_CONTROL_HALT_IMM 0x00000002 +#define MAC_CONTROL_HALT_REQ 0x00000001 + +/* CAM CONTROL register. */ +#define CAM_CONTROL_COMP_EN 0x00000010 +#define CAM_CONTROL_NEG_CAM 0x00000008 +#define CAM_CONTROL_BROAD_ACC 0x00000004 +#define CAM_CONTROL_GROUP_ACC 0x00000002 +#define CAM_CONTROL_STATION_ACC 0x00000001 + +/* TRANSMIT CONTROL register. */ +#define TX_CTL_EN_COMP 0x00004000 +#define TX_CTL_EN_TX_PAR 0x00002000 +#define TX_CTL_EN_LATE_COLL 0x00001000 +#define TX_CTL_EN_EX_COLL 0x00000800 +#define TX_CTL_EN_L_CARR 0x00000400 +#define TX_CTL_EN_EX_DEFER 0x00000200 +#define TX_CTL_EN_UNDER 0x00000100 +#define TX_CTL_MII10 0x00000080 +#define TX_CTL_SD_PAUSE 0x00000040 +#define TX_CTL_NO_EX_DEF0 0x00000020 +#define TX_CTL_F_BACK 0x00000010 +#define TX_CTL_NO_CRC 0x00000008 +#define TX_CTL_NO_PAD 0x00000004 +#define TX_CTL_TX_HALT 0x00000002 +#define TX_CTL_TX_EN 0x00000001 + +/* TRANSMIT STATUS register. */ +#define TX_STATUS_SQ_ERR 0x00010000 +#define TX_STATUS_TX_HALTED 0x00008000 +#define TX_STATUS_COMP 0x00004000 +#define TX_STATUS_TX_PAR 0x00002000 +#define TX_STATUS_LATE_COLL 0x00001000 +#define TX_STATUS_TX10_STAT 0x00000800 +#define TX_STATUS_L_CARR 0x00000400 +#define TX_STATUS_EX_DEFER 0x00000200 +#define TX_STATUS_UNDER 0x00000100 +#define TX_STATUS_IN_TX 0x00000080 +#define TX_STATUS_PAUSED 0x00000040 +#define TX_STATUS_TX_DEFERRED 0x00000020 +#define TX_STATUS_EX_COLL 0x00000010 +#define TX_STATUS_TX_COLL_SHF 0 +#define TX_STATUS_TX_COLL_MSK (0xf << TX_STATUS_TX_COLL_SHF) + +/* RECEIVE CONTROL register. */ +#define RX_CTL_EN_GOOD 0x00004000 +#define RX_CTL_EN_RX_PAR 0x00002000 +#define RX_CTL_EN_LONG_ERR 0x00000800 +#define RX_CTL_EN_OVER 0x00000400 +#define RX_CTL_EN_CRC_ERR 0x00000200 +#define RX_CTL_EN_ALIGN 0x00000100 +#define RX_CTL_IGNORE_CRC 0x00000040 +#define RX_CTL_PASS_CTL 0x00000020 +#define RX_CTL_STRIP_CRC 0x00000010 +#define RX_CTL_SHORT_EN 0x00000008 +#define RX_CTL_LONG_EN 0x00000004 +#define RX_CTL_RX_HALT 0x00000002 +#define RX_CTL_RX_EN 0x00000001 + +/* RECEIVE STATUS register. */ +#define RX_STATUS_RX_HALTED 0x00008000 +#define RX_STATUS_GOOD 0x00004000 +#define RX_STATUS_RX_PAR 0x00002000 +#define RX_STATUS_LONG_ERR 0x00000800 +#define RX_STATUS_OVERFLOW 0x00000400 +#define RX_STATUS_CRC_ERR 0x00000200 +#define RX_STATUS_ALIGN_ERR 0x00000100 +#define RX_STATUS_RX10_STAT 0x00000080 +#define RX_STATUS_INT_RX 0x00000040 +#define RX_STATUS_CTL_RECD 0x00000020 + +/* MD_CA register. */ +#define MD_CA_PRE_SUP 0x00001000 +#define MD_CA_BUSY 0x00000800 +#define MD_CA_WR 0x00000400 +#define MD_CA_PHY_SHF 5 +#define MD_CA_PHY_MSK (0x1f << MD_CA_PHY_SHF) +#define MD_CA_ADDR_SHF 0 +#define MD_CA_ADDR_MSK (0x1f << MD_CA_ADDR_SHF) + +/* Tx Status/Control. */ +#define TX_STAT_CTL_OWNER_SHF 30 +#define TX_STAT_CTL_OWNER_MSK (0x3 << TX_STAT_CTL_OWNER_SHF) +#define TX_STAT_CTL_FRAME_SHF 27 +#define TX_STAT_CTL_FRAME_MSK (0x7 << TX_STAT_CTL_FRAME_SHF) +#define TX_STAT_CTL_STATUS_SHF 11 +#define TX_STAT_CTL_STATUS_MSK (0x1ffff << TX_STAT_CTL_STATUS_SHF) +#define TX_STAT_CTL_LENGTH_SHF 0 +#define TX_STAT_CTL_LENGTH_MSK (0x7ff << TX_STAT_CTL_LENGTH_SHF) + +#define TX_STAT_CTL_ERROR_MSK ((TX_STATUS_SQ_ERR | \ + TX_STATUS_TX_HALTED | \ + TX_STATUS_TX_PAR | \ + TX_STATUS_LATE_COLL | \ + TX_STATUS_L_CARR | \ + TX_STATUS_EX_DEFER | \ + TX_STATUS_UNDER | \ + TX_STATUS_PAUSED | \ + TX_STATUS_TX_DEFERRED | \ + TX_STATUS_EX_COLL | \ + TX_STATUS_TX_COLL_MSK) \ + << TX_STAT_CTL_STATUS_SHF) +#define TX_STAT_CTL_INT_AFTER_TX 0x4 + +/* Rx Status/Control. */ +#define RX_STAT_CTL_OWNER_SHF 30 +#define RX_STAT_CTL_OWNER_MSK (0x3 << RX_STAT_CTL_OWNER_SHF) +#define RX_STAT_CTL_STATUS_SHF 11 +#define RX_STAT_CTL_STATUS_MSK (0xffff << RX_STAT_CTL_STATUS_SHF) +#define RX_STAT_CTL_LENGTH_SHF 0 +#define RX_STAT_CTL_LENGTH_MSK (0x7ff << RX_STAT_CTL_LENGTH_SHF) + + + +/* The SAA9730 (LAN) controller register map, as seen via the PCI-bus. */ +#define SAA9730_LAN_REGS_ADDR 0x20400 + +struct lan_saa9730_regmap { + volatile unsigned int TxBuffA; /* 0x20400 */ + volatile unsigned int TxBuffB; /* 0x20404 */ + volatile unsigned int RxBuffA; /* 0x20408 */ + volatile unsigned int RxBuffB; /* 0x2040c */ + volatile unsigned int PacketCount; /* 0x20410 */ + volatile unsigned int Ok2Use; /* 0x20414 */ + volatile unsigned int LanDmaCtl; /* 0x20418 */ + volatile unsigned int Timeout; /* 0x2041c */ + volatile unsigned int DmaStatus; /* 0x20420 */ + volatile unsigned int DmaTest; /* 0x20424 */ + volatile unsigned char filler20428[0x20430 - 0x20428]; + volatile unsigned int PauseCount; /* 0x20430 */ + volatile unsigned int RemotePauseCount; /* 0x20434 */ + volatile unsigned char filler20438[0x20440 - 0x20438]; + volatile unsigned int MacCtl; /* 0x20440 */ + volatile unsigned int CamCtl; /* 0x20444 */ + volatile unsigned int TxCtl; /* 0x20448 */ + volatile unsigned int TxStatus; /* 0x2044c */ + volatile unsigned int RxCtl; /* 0x20450 */ + volatile unsigned int RxStatus; /* 0x20454 */ + volatile unsigned int StationMgmtData; /* 0x20458 */ + volatile unsigned int StationMgmtCtl; /* 0x2045c */ + volatile unsigned int CamAddress; /* 0x20460 */ + volatile unsigned int CamData; /* 0x20464 */ + volatile unsigned int CamEnable; /* 0x20468 */ + volatile unsigned char filler2046c[0x20500 - 0x2046c]; + volatile unsigned int DebugPCIMasterAddr; /* 0x20500 */ + volatile unsigned int DebugLanTxStateMachine; /* 0x20504 */ + volatile unsigned int DebugLanRxStateMachine; /* 0x20508 */ + volatile unsigned int DebugLanTxFifoPointers; /* 0x2050c */ + volatile unsigned int DebugLanRxFifoPointers; /* 0x20510 */ + volatile unsigned int DebugLanCtlStateMachine; /* 0x20514 */ +}; +typedef volatile struct lan_saa9730_regmap t_lan_saa9730_regmap; + + +/* EVM interrupt control registers. */ +#define EVM_LAN_INT 0x00010000 +#define EVM_MASTER_EN 0x00000001 + +/* The SAA9730 (EVM) controller register map, as seen via the PCI-bus. */ +#define SAA9730_EVM_REGS_ADDR 0x02000 + +struct evm_saa9730_regmap { + volatile unsigned int InterruptStatus1; /* 0x2000 */ + volatile unsigned int InterruptEnable1; /* 0x2004 */ + volatile unsigned int InterruptMonitor1; /* 0x2008 */ + volatile unsigned int Counter; /* 0x200c */ + volatile unsigned int CounterThreshold; /* 0x2010 */ + volatile unsigned int CounterControl; /* 0x2014 */ + volatile unsigned int GpioControl1; /* 0x2018 */ + volatile unsigned int InterruptStatus2; /* 0x201c */ + volatile unsigned int InterruptEnable2; /* 0x2020 */ + volatile unsigned int InterruptMonitor2; /* 0x2024 */ + volatile unsigned int GpioControl2; /* 0x2028 */ + volatile unsigned int InterruptBlock1; /* 0x202c */ + volatile unsigned int InterruptBlock2; /* 0x2030 */ +}; +typedef volatile struct evm_saa9730_regmap t_evm_saa9730_regmap; + + +struct lan_saa9730_private { + /* Pointer for the SAA9730 LAN controller register set. */ + t_lan_saa9730_regmap *lan_saa9730_regs; + + /* Pointer to the SAA9730 EVM register. */ + t_evm_saa9730_regmap *evm_saa9730_regs; + + /* TRUE if the next buffer to write is RxBuffA, FALSE if RxBuffB. */ + unsigned char NextRcvToUseIsA; + /* Rcv buffer Index. */ + unsigned char NextRcvPacketIndex; + + /* Index of next packet to use in that buffer. */ + unsigned char NextTxmPacketIndex; + /* Next buffer index. */ + unsigned char NextTxmBufferIndex; + + /* Index of first pending packet ready to send. */ + unsigned char PendingTxmPacketIndex; + /* Pending buffer index. */ + unsigned char PendingTxmBufferIndex; + + unsigned char DmaRcvPackets; + unsigned char DmaTxmPackets; + + unsigned char RcvAIndex; /* index into RcvBufferSpace[] for Blk A */ + unsigned char RcvBIndex; /* index into RcvBufferSpace[] for Blk B */ + + unsigned int + TxmBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_TXM_Q_SIZE]; + unsigned int + RcvBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_RCV_Q_SIZE]; + unsigned int TxBufferFree[LAN_SAA9730_BUFFERS]; + + unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6]; + + struct net_device_stats stats; +}; + +#endif /* _SAA9730_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c --- v2.4.3/linux/drivers/net/sgiseeq.c Tue Mar 6 19:28:35 2001 +++ linux/drivers/net/sgiseeq.c Thu Apr 12 12:15:25 2001 @@ -206,7 +206,7 @@ void sgiseeq_dump_rings(void) { - static int once = 0; + static int once; struct sgiseeq_rx_desc *r = gpriv->srings.rx_desc; struct sgiseeq_tx_desc *t = gpriv->srings.tx_desc; volatile struct hpc3_ethregs *hregs = gpriv->hregs; @@ -611,7 +611,7 @@ int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs, struct hpc3_ethregs *hregs, int irq) { - static unsigned version_printed = 0; + static unsigned version_printed; int i; struct sgiseeq_private *sp; @@ -704,7 +704,7 @@ int sgiseeq_probe(struct net_device *dev) { - static int initialized = 0; + static int initialized; char *ep; if (initialized) /* Already initialized? */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.4.3/linux/drivers/net/sis900.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/sis900.c Wed Apr 11 21:17:59 2001 @@ -1,11 +1,11 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.07.08 Jan. 8 2001 + Revision: 1.07.11 Apr. 10 2001 Modified from the driver which is originally written by Donald Becker. This software may be used and distributed according to the terms - of the GNU General Public License (GPL), incorporated herein by reference. + of the GNU Public License (GPL), incorporated herein by reference. Drivers based on this skeleton fall under the GPL and must retain the authorship (implicit copyright) notice. @@ -18,6 +18,8 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3 + Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support Rev 1.07.09 Feb. 9 2001 Dave Jones <davej@suse.de> PCI enable cleanup Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix @@ -45,7 +47,7 @@ #include <linux/timer.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/netdevice.h> @@ -61,9 +63,9 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.07.09 2/9/2001\n"; +"sis900.c: v1.07.11 4/10/2001\n"; -static int max_interrupt_work = 20; +static int max_interrupt_work = 40; static int multicast_filter_limit = 128; #define sis900_debug debug @@ -91,31 +93,33 @@ }; MODULE_DEVICE_TABLE (pci, sis900_pci_tbl); -static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); -static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); -static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); -static void rtl8201_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); +static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex); static struct mii_chip_info { const char * name; u16 phy_id0; u16 phy_id1; - void (*read_mode) (struct net_device *net_dev, int phy_addr, int *speed, int *duplex); + u8 phy_types; +#define HOME 0x0001 +#define LAN 0x0002 +#define MIX 0x0003 } mii_chip_table[] = { - {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode}, - {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode}, - {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9, amd79c901_read_mode}, - {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, amd79c901_read_mode}, - {"ICS 1893 Integrated PHYceiver" , 0x0015, 0xf441,ics1893_read_mode}, - {"RTL 8201 10/100Mbps Phyceiver" , 0x0000, 0x8201,rtl8201_read_mode}, + { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, + { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, + { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, + { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, + { "ICS LAN PHY", 0x0015, 0xF440, LAN }, + { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, {0,}, }; struct mii_phy { struct mii_phy * next; - struct mii_chip_info * chip_info; int phy_addr; + u16 phy_id0; + u16 phy_id1; u16 status; + u8 phy_types; }; typedef struct _BufferDesc { @@ -131,11 +135,13 @@ spinlock_t lock; struct mii_phy * mii; + struct mii_phy * first_mii; /* record the first mii structure */ unsigned int cur_phy; - struct timer_list timer; /* Link status detection timer. */ + struct timer_list timer; /* Link status detection timer. */ + u8 autong_complete; /* 1: auto-negotiate complete */ - unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ + unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ unsigned int cur_tx, dirty_tx; /* The saved address of a sent/receive-in-place packet buffer */ @@ -171,11 +177,16 @@ static int sis900_close(struct net_device *net_dev); static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd); static struct net_device_stats *sis900_get_stats(struct net_device *net_dev); -static u16 sis900_compute_hashtable_index(u8 *addr); +static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision); static void set_rx_mode(struct net_device *net_dev); static void sis900_reset(struct net_device *net_dev); static void sis630_set_eq(struct net_device *net_dev, u8 revision); static int sis900_set_config(struct net_device *dev, struct ifmap *map); +static u16 sis900_default_phy(struct net_device * net_dev); +static void sis900_set_capability( struct net_device *net_dev ,struct mii_phy *phy); +static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr); +static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr); +static void sis900_set_mode (long ioaddr, int speed, int duplex); /** * sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model @@ -239,6 +250,44 @@ return 1; } + +/** + * sis635_get_mac_addr: - Get MAC address for SIS635 model + * @pci_dev: the sis900 pci device + * @net_dev: the net device to get address for + * + * SiS635 model, set MAC Reload Bit to load Mac address from APC + * to rfdr. rfdr is accessed through rfcr. MAC address is read into + * @net_dev->dev_addr. + */ + +static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +{ + long ioaddr = net_dev->base_addr; + u32 rfcrSave; + u32 i; + + rfcrSave = inl(rfcr + ioaddr); + + outl(rfcrSave | RELOAD, ioaddr + cr); + outl(0, ioaddr + cr); + + /* disable packet filtering before setting filter */ + outl(rfcrSave & ~RFEN, rfcr + ioaddr); + + /* load MAC addr to filter data register */ + for (i = 0 ; i < 3 ; i++) { + outl((i << RFADDR_shift), ioaddr + rfcr); + *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr); + } + + /* enable packet filitering */ + outl(rfcrSave | RFEN, rfcr + ioaddr); + + return 1; +} + + /** * sis900_probe: - Probe for sis900 device * @pci_dev: the sis900 pci device @@ -253,64 +302,41 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct sis900_private *sis_priv; - long ioaddr; struct net_device *net_dev; - int irq; + long ioaddr; int i, ret; u8 revision; char *card_name = card_names[pci_id->driver_data]; /* setup various bits in PCI command register */ - ret = pci_enable_device (pci_dev); - if (ret) return ret; - + ret = pci_enable_device(pci_dev); + if(ret) return ret; + i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK); - if (i) { - printk(KERN_ERR "sis900.c: architecture does not support " - "32bit PCI busmaster DMA\n"); + if(i){ + printk(KERN_ERR "sis900.c: architecture does not support" + "32bit PCI busmaster DMA\n"); return i; } - + pci_set_master(pci_dev); - - irq = pci_dev->irq; - ioaddr = pci_resource_start(pci_dev, 0); - + net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; SET_MODULE_OWNER(net_dev); + /* We do a request_region() to register /proc/ioports info. */ + ioaddr = pci_resource_start(pci_dev, 0); ret = pci_request_regions(pci_dev, "sis900"); if (ret) goto err_out; - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV) - ret = sis630e_get_mac_addr(pci_dev, net_dev); - else if (revision == SIS630S_900_REV) - ret = sis630e_get_mac_addr(pci_dev, net_dev); - else - ret = sis900_get_mac_addr(pci_dev, net_dev); - - if (ret == 0) { - ret = -ENODEV; - goto err_out_region; - } - sis_priv = net_dev->priv; - - /* We do a request_region() to register /proc/ioports info. */ net_dev->base_addr = ioaddr; - net_dev->irq = irq; + net_dev->irq = pci_dev->irq; sis_priv->pci_dev = pci_dev; spin_lock_init(&sis_priv->lock); - - /* probe for mii transciver */ - if (sis900_mii_probe(net_dev) == 0) { - ret = -ENODEV; - goto err_out_region; - } pci_set_drvdata(pci_dev, net_dev); @@ -324,25 +350,47 @@ net_dev->do_ioctl = &mii_ioctl; net_dev->tx_timeout = sis900_tx_timeout; net_dev->watchdog_timeo = TX_TIMEOUT; - + ret = register_netdev(net_dev); if (ret) goto err_out_cleardev; + + /* Get Mac address according to the chip revision */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); + ret = 0; + + if (revision == SIS630E_900_REV) + ret = sis630e_get_mac_addr(pci_dev, net_dev); + else if ((revision > 0x81) && (revision <= 0x90) ) + ret = sis635_get_mac_addr(pci_dev, net_dev); + else + ret = sis900_get_mac_addr(pci_dev, net_dev); + + if (ret == 0) { + ret = -ENODEV; + goto err_out_region; + } + + /* probe for mii transciver */ + if (sis900_mii_probe(net_dev) == 0) { + ret = -ENODEV; + goto err_out_region; + } /* print some information about our NIC */ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, - card_name, ioaddr, irq); + card_name, ioaddr, net_dev->irq); for (i = 0; i < 5; i++) printk("%2.2x:", (u8)net_dev->dev_addr[i]); printk("%2.2x.\n", net_dev->dev_addr[i]); return 0; -err_out_cleardev: - pci_set_drvdata(pci_dev, NULL); -err_out_region: + err_out_cleardev: + pci_set_drvdata(pci_dev, NULL); + err_out_region: pci_release_regions(pci_dev); -err_out: + err_out: kfree(net_dev); return ret; } @@ -350,7 +398,7 @@ /** * sis900_mii_probe: - Probe MII PHY for sis900 * @net_dev: the net device to probe for - * + * * Search for total of 32 possible mii phy addresses. * Identify and set current phy if found one, * return error if it failed to found. @@ -359,59 +407,83 @@ static int __init sis900_mii_probe (struct net_device * net_dev) { struct sis900_private * sis_priv = net_dev->priv; + u16 poll_bit = MII_STAT_LINK, status = 0; + unsigned int timeout = jiffies + 5 * HZ; int phy_addr; u8 revision; sis_priv->mii = NULL; /* search for total of 32 possible mii phy addresses */ - for (phy_addr = 0; phy_addr < 32; phy_addr++) { + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + struct mii_phy * mii_phy = NULL; u16 mii_status; - u16 phy_id0, phy_id1; int i; - mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); + mii_phy = NULL; + for(i = 0; i < 2; i++) + mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); + if (mii_status == 0xffff || mii_status == 0x0000) /* the mii is not accessable, try next one */ continue; + + if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) { + printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n"); + return 0; + } + + mii_phy->phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0); + mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1); + mii_phy->phy_addr = phy_addr; + mii_phy->status = mii_status; + mii_phy->next = sis_priv->mii; + sis_priv->mii = mii_phy; + sis_priv->first_mii = mii_phy; - phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0); - phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1); - - /* search our mii table for the current mii */ for (i = 0; mii_chip_table[i].phy_id1; i++) - if (phy_id0 == mii_chip_table[i].phy_id0 && - phy_id1 == mii_chip_table[i].phy_id1) { - struct mii_phy * mii_phy; - - printk(KERN_INFO - "%s: %s transceiver found at address %d.\n", - net_dev->name, mii_chip_table[i].name, - phy_addr); - if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { - mii_phy->chip_info = mii_chip_table+i; - mii_phy->phy_addr = phy_addr; - mii_phy->status = mdio_read(net_dev, phy_addr, - MII_STATUS); - mii_phy->next = sis_priv->mii; - sis_priv->mii = mii_phy; - } - /* the current mii is on our mii_info_table, - try next address */ + if ((mii_phy->phy_id0 == mii_chip_table[i].phy_id0 ) && + ((mii_phy->phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){ + mii_phy->phy_types = mii_chip_table[i].phy_types; + if (mii_chip_table[i].phy_types == MIX) + mii_phy->phy_types = + (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME; + printk(KERN_INFO "%s: %s transceiver found at address %d.\n", + net_dev->name, mii_chip_table[i].name, phy_addr); break; } + + if( !mii_chip_table[i].phy_id1 ) + printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n", + net_dev->name, phy_addr); } - + if (sis_priv->mii == NULL) { printk(KERN_INFO "%s: No MII transceivers found!\n", net_dev->name); return 0; } - /* arbitrary choose that last PHY as current PHY */ - sis_priv->cur_phy = sis_priv->mii->phy_addr; - printk(KERN_INFO "%s: Using %s as default\n", net_dev->name, - sis_priv->mii->chip_info->name); + /* select default PHY for mac */ + sis_priv->mii = NULL; + sis900_default_phy( net_dev ); + + /* Reset phy if default phy is internal sis900 */ + if ((sis_priv->mii->phy_id0 == 0x001D) && + ((sis_priv->mii->phy_id1&0xFFF0) == 0x8000)) + status = sis900_reset_phy(net_dev, sis_priv->cur_phy); + + if(status & MII_STAT_LINK){ + while (poll_bit) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: reset phy and link down now\n", net_dev->name); + return -ETIME; + } + } + } pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); if (revision == SIS630E_900_REV) { @@ -420,7 +492,7 @@ mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22); mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00); mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0); - mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000); + //mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000); } if (sis_priv->mii->status & MII_STAT_LINK) @@ -431,6 +503,86 @@ return 1; } +/** + * sis900_default_phy: - Select default PHY for sis900 mac. + * @net_dev: the net device to probe for + * + * Select first detected PHY with link as default. + * If no one is link on, select PHY whose types is HOME as default. + * If HOME doesn't exist, select LAN. + */ + +static u16 sis900_default_phy(struct net_device * net_dev) +{ + struct sis900_private * sis_priv = net_dev->priv; + struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL; + u16 status; + + for( phy=sis_priv->first_mii; phy; phy=phy->next ){ + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + + /* Link ON & Not select deafalut PHY */ + if ( (status & MII_STAT_LINK) && !(default_phy) ) + default_phy = phy; + else{ + status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL); + mdio_write(net_dev, phy->phy_addr, MII_CONTROL, + status | MII_CNTL_AUTO | MII_CNTL_ISOLATE); + if( phy->phy_types == HOME ) + phy_home = phy; + } + } + + if( (!default_phy) && phy_home ) + default_phy = phy_home; + else if(!default_phy) + default_phy = sis_priv->first_mii; + + if( sis_priv->mii != default_phy ){ + sis_priv->mii = default_phy; + sis_priv->cur_phy = default_phy->phy_addr; + printk(KERN_INFO "%s: Using transceiver found at address %d as default\n", net_dev->name,sis_priv->cur_phy); + } + + status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); + status &= (~MII_CNTL_ISOLATE); + + mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + + return status; +} + + +/** + * sis900_set_capability: - set the media capability of network adapter. + * @net_dev : the net device to probe for + * @mii_phy : default PHY + * + * Set the media capability of network adapter according to + * mii status register. It's necessary before auto-negotiate. + */ + +static void sis900_set_capability( struct net_device *net_dev , struct mii_phy *phy ) +{ + u16 cap; + u16 status; + + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); + + cap = MII_NWAY_CSMA_CD | + ((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) | + ((phy->status & MII_STAT_CAN_TX) ? MII_NWAY_TX:0) | + ((phy->status & MII_STAT_CAN_T_FDX) ? MII_NWAY_T_FDX:0)| + ((phy->status & MII_STAT_CAN_T) ? MII_NWAY_T:0); + + mdio_write(net_dev, phy->phy_addr, MII_ANADV, cap); +} + + /* Delay between EEPROM clock transitions. */ #define eeprom_delay() inl(ee_addr) @@ -605,6 +757,30 @@ return; } + +/** + * sis900_reset_phy: - reset sis900 mii phy. + * @net_dev: the net device to write + * @phy_addr: default phy address + * + * Some specific phy can't work properly without reset. + * This function will be called during initialization and + * link status change from ON to DOWN. + */ + +static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr) +{ + int i = 0; + u16 status; + + while (i++ < 2) + status = mdio_read(net_dev, phy_addr, MII_STATUS); + + mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET ); + + return status; +} + /** * sis900_open: - open sis900 device * @net_dev: the net device to open @@ -626,9 +802,7 @@ /* Equalizer workaround Rule */ pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || - revision == SIS630A_900_REV) - sis630_set_eq(net_dev,revision); + sis630_set_eq(net_dev, revision); ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev); if (ret) @@ -679,7 +853,7 @@ rfcrSave = inl(rfcr + ioaddr); /* disable packet filtering before setting filter */ - outl(rfcrSave & ~RFEN, rfcr); + outl(rfcrSave & ~RFEN, rfcr + ioaddr); /* load MAC addr to filter data register */ for (i = 0 ; i < 3 ; i++) { @@ -820,7 +994,11 @@ int i, maxcount=10; struct pci_dev *dev=NULL; - if ((dev = pci_find_device(SIS630_DEVICE_ID, SIS630_VENDOR_ID, dev))) + if ( !(revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || + revision == SIS630A_900_REV) ) + return; + + if ((dev = pci_find_device(SIS630_VENDOR_ID, SIS630_DEVICE_ID, dev))) pci_read_config_byte(dev, PCI_CLASS_REVISION, &host_bridge_rev); if (netif_carrier_ok(net_dev)) { @@ -842,13 +1020,6 @@ else if (max_value >= 15) eq_value=(max_value == min_value) ? max_value+6 : max_value+5; } - /* 630A0 rule to determine the equalizer value */ - if (revision == SIS630A_900_REV && host_bridge_rev == SIS630A0) { - if (max_value < 5) - eq_value=max_value+3; - else if (max_value >= 5) - eq_value=max_value+5; - } /* 630B0&B1 rule to determine the equalizer value */ if (revision == SIS630A_900_REV && (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) { @@ -865,7 +1036,11 @@ } else { reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); - mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF); + if (revision == SIS630A_900_REV && + (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2200) & 0xBFFF); + else + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF); } return; } @@ -887,60 +1062,52 @@ u16 status; u8 revision; - status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); - status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + if (!sis_priv->autong_complete){ + int speed, duplex = 0; - /* current mii phy is failed to link, try another one */ - while (!(status & MII_STAT_LINK)) { - if (mii_phy->next == NULL) { - if (netif_carrier_ok(net_dev)) { - /* link stat change from ON to OFF */ - next_tick = HZ; - netif_carrier_off(net_dev); - - /* Equalizer workaround Rule */ - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || - revision == SIS630A_900_REV) - sis630_set_eq(net_dev, revision); - - printk(KERN_INFO "%s: Media Link Off\n", - net_dev->name); - } - sis_priv->timer.expires = jiffies + next_tick; - add_timer(&sis_priv->timer); - return; + sis900_read_mode(net_dev, &speed, &duplex); + if (duplex){ + sis900_set_mode(net_dev->base_addr, speed, duplex); + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + sis630_set_eq(net_dev, revision); } - mii_phy = mii_phy->next; - status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS); - } - if (!netif_carrier_ok(net_dev)) { - /* link stat change forn OFF to ON, read and report link mode */ - netif_carrier_on(net_dev); - next_tick = 5*HZ; + sis_priv->timer.expires = jiffies + HZ; + add_timer(&sis_priv->timer); + return; + } - /* Equalizer workaround Rule */ - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || - revision == SIS630A_900_REV) - sis630_set_eq(net_dev, revision); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); - /* change what cur_phy means */ - if (mii_phy->phy_addr != sis_priv->cur_phy) { - printk(KERN_INFO "%s: Changing transceiver to %s\n", - net_dev->name, mii_phy->chip_info->name); - /* disable previous PHY */ - status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); - mdio_write(net_dev, sis_priv->cur_phy, - MII_CONTROL, status | MII_CNTL_ISOLATE); - /* enable next PHY */ - status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL); - mdio_write(net_dev, mii_phy->phy_addr, - MII_CONTROL, status & ~MII_CNTL_ISOLATE); - sis_priv->cur_phy = mii_phy->phy_addr; + /* Link OFF -> ON */ + if (!netif_carrier_ok(net_dev)) { + LookForLink: + /* Search for new PHY */ + status = sis900_default_phy(net_dev); + mii_phy = sis_priv->mii; + + if (status & MII_STAT_LINK){ + sis900_check_mode(net_dev, mii_phy); + netif_carrier_on(net_dev); } - sis900_check_mode(net_dev, mii_phy); + } + /* Link ON -> OFF */ + else { + if (!(status & MII_STAT_LINK)){ + netif_carrier_off(net_dev); + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + + /* Change mode issue */ + if ((mii_phy->phy_id0 == 0x001D) && + ((mii_phy->phy_id1 & 0xFFF0) == 0x8000)) + sis900_reset_phy(net_dev, sis_priv->cur_phy); + + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + sis630_set_eq(net_dev, revision); + + goto LookForLink; + } } sis_priv->timer.expires = jiffies + next_tick; @@ -952,8 +1119,11 @@ * @net_dev: the net device to be checked * @mii_phy: the mii phy * - * call mii_phy->chip_info->read_mode function - * to check the speed and duplex mode for sis900 + * Older driver gets the media mode from mii status output + * register. Now we set our media capability and auto-negotiate + * to get the upper bound of speed and duplex between two ends. + * If the types of mii phy is HOME, it doesn't need to auto-negotiate + * and autong_complete should be set to 1. */ static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy) @@ -961,12 +1131,44 @@ struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int speed, duplex; - u32 tx_flags = 0, rx_flags = 0; - mii_phy->chip_info->read_mode(net_dev, sis_priv->cur_phy, &speed, &duplex); + if( mii_phy->phy_types == LAN ){ + outl( ~EXD & inl( ioaddr + cfg ), ioaddr + cfg); + sis900_set_capability(net_dev , mii_phy); + sis900_auto_negotiate(net_dev, sis_priv->cur_phy); + }else{ + outl(EXD | inl( ioaddr + cfg ), ioaddr + cfg); + speed = HW_SPEED_HOME; + duplex = FDX_CAPABLE_HALF_SELECTED; + sis900_set_mode(ioaddr, speed, duplex); + sis_priv->autong_complete = 1; + } +} - tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); - rx_flags = RX_DMA_BURST << RxMXDMA_shift; +/** + * sis900_set_mode: - Set the media mode of mac register. + * @speed : the transmit speed to be determined + * @duplex: the duplex mode to be determined + * + * Set the media mode of mac register txcfg/rxcfg according to + * speed and duplex of phy. Bit EDB_MASTER_EN indicates the EDB + * bus is used instead of PCI bus. When this bit is set 1, the + * Max DMA Burst Size for TX/RX DMA should be no larger than 16 + * double words. + */ + +static void sis900_set_mode (long ioaddr, int speed, int duplex) +{ + u32 tx_flags = 0, rx_flags = 0; + + if( inl(ioaddr + cfg) & EDB_MASTER_EN ){ + tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + rx_flags = DMA_BURST_64 << RxMXDMA_shift; + } + else{ + tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + rx_flags = DMA_BURST_512 << RxMXDMA_shift; + } if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) { rx_flags |= (RxDRNT_10 << RxDRNT_shift); @@ -987,184 +1189,86 @@ } /** - * sis900_read_mode: - read media mode for sis900 internal phy + * sis900_auto_negotiate: Set the Auto-Negotiation Enable/Reset bit. * @net_dev: the net device to read mode for * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined * - * read MII_STSOUT register from sis900 internal phy - * to determine the speed and duplex mode for sis900 + * If the adapter is link-on, set the auto-negotiate enable/reset bit. + * autong_complete should be set to 0 when starting auto-negotiation. + * autong_complete should be set to 1 if we didn't start auto-negotiation. + * sis900_timer will wait for link on again if autong_complete = 0. */ -static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) { + struct sis900_private *sis_priv = net_dev->priv; int i = 0; u32 status; - - /* STSOUT register is Latched on Transition, read operation updates it */ + while (i++ < 2) - status = mdio_read(net_dev, phy_addr, MII_STSOUT); - - if (status & MII_STSOUT_SPD) - *speed = HW_SPEED_100_MBPS; - else - *speed = HW_SPEED_10_MBPS; - - if (status & MII_STSOUT_DPLX) - *duplex = FDX_CAPABLE_FULL_SELECTED; - else - *duplex = FDX_CAPABLE_HALF_SELECTED; + status = mdio_read(net_dev, phy_addr, MII_STATUS); - if (status & MII_STSOUT_LINK_FAIL) + if (!(status & MII_STAT_LINK)){ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - else - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); + sis_priv->autong_complete = 1; + netif_carrier_off(net_dev); + return; + } + + /* (Re)start AutoNegotiate */ + mdio_write(net_dev, phy_addr, MII_CONTROL, + MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + sis_priv->autong_complete = 0; } + /** - * amd79c901_read_mode: - read media mode for amd79c901 phy + * sis900_read_mode: - read media mode for sis900 internal phy * @net_dev: the net device to read mode for - * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined + * @speed : the transmit speed to be determined + * @duplex : the duplex mode to be determined * - * read MII_STATUS register from amd79c901 phy - * to determine the speed and duplex mode for sis900 + * The capability of remote end will be put in mii register autorec + * after auto-negotiation. Use AND operation to get the upper bound + * of speed and duplex between two ends. */ -static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex) { - int i; - u16 status; + struct sis900_private *sis_priv = net_dev->priv; + int phy_addr = sis_priv->cur_phy; + u32 status; + u16 autoadv, autorec; + int i = 0; - for (i = 0; i < 2; i++) + while (i++ < 2) status = mdio_read(net_dev, phy_addr, MII_STATUS); - if (status & MII_STAT_CAN_AUTO) { - /* 10BASE-T PHY */ - for (i = 0; i < 2; i++) - status = mdio_read(net_dev, phy_addr, MII_STATUS_SUMMARY); - if (status & MII_STSSUM_SPD) - *speed = HW_SPEED_100_MBPS; - else - *speed = HW_SPEED_10_MBPS; - if (status & MII_STSSUM_DPLX) - *duplex = FDX_CAPABLE_FULL_SELECTED; - else - *duplex = FDX_CAPABLE_HALF_SELECTED; + if (!(status & MII_STAT_LINK)) + return; - if (status & MII_STSSUM_LINK) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - } - else { - /* HomePNA */ - *speed = HW_SPEED_HOME; - *duplex = FDX_CAPABLE_HALF_SELECTED; - if (status & MII_STAT_LINK) - printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", - net_dev->name); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - } -} - -/** - * ics1893_read_mode: - read media mode for ICS1893 PHY - * @net_dev: the net device to read mode for - * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined - * - * ICS1893 PHY use Quick Poll Detailed Status register - * to determine the speed and duplex mode for sis900 - */ + /* AutoNegotiate completed */ + autoadv = mdio_read(net_dev, phy_addr, MII_ANADV); + autorec = mdio_read(net_dev, phy_addr, MII_ANLPAR); + status = autoadv & autorec; -static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) -{ - int i = 0; - u32 status; - - /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */ - for (i = 0; i < 2; i++) - status = mdio_read(net_dev, phy_addr, MII_QPDSTS); - - if (status & MII_STSICS_SPD) + if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX)) *speed = HW_SPEED_100_MBPS; else *speed = HW_SPEED_10_MBPS; - - if (status & MII_STSICS_DPLX) + if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) *duplex = FDX_CAPABLE_FULL_SELECTED; else *duplex = FDX_CAPABLE_HALF_SELECTED; - if (status & MII_STSICS_LINKSTS) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); -} - -/** - * rtl8201_read_mode: - read media mode for rtl8201 phy - * @net_dev: the net device to read mode for - * @phy_addr: mii phy address - * @speed: the transmit speed to be determined - * @duplex: the duplex mode to be determined - * - * read MII_STATUS register from rtl8201 phy - * to determine the speed and duplex mode for sis900 - */ - -static void rtl8201_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) -{ - u32 status; - - status = mdio_read(net_dev, phy_addr, MII_STATUS); - - if (status & MII_STAT_CAN_TX_FDX) { - *speed = HW_SPEED_100_MBPS; - *duplex = FDX_CAPABLE_FULL_SELECTED; - } - else if (status & MII_STAT_CAN_TX) { - *speed = HW_SPEED_100_MBPS; - *duplex = FDX_CAPABLE_HALF_SELECTED; - } - else if (status & MII_STAT_CAN_T_FDX) { - *speed = HW_SPEED_10_MBPS; - *duplex = FDX_CAPABLE_FULL_SELECTED; - } - else if (status & MII_STAT_CAN_T) { - *speed = HW_SPEED_10_MBPS; - *duplex = FDX_CAPABLE_HALF_SELECTED; - } - - if (status & MII_STAT_LINK) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - else - printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + sis_priv->autong_complete = 1; + + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); } /** @@ -1628,83 +1732,81 @@ u16 status; - /* - )*/ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - /* we switch on the ifmap->port field. I couldn't find anything - like a definition or standard for the values of that field. - I think the meaning of those values is device specific. But - since I would like to change the media type via the ifconfig - command I use the definition from linux/netdevice.h - (which seems to be different from the ifport(pcmcia) definition) - */ + /* we switch on the ifmap->port field. I couldn't find anything + like a definition or standard for the values of that field. + I think the meaning of those values is device specific. But + since I would like to change the media type via the ifconfig + command I use the definition from linux/netdevice.h + (which seems to be different from the ifport(pcmcia) definition) + */ switch(map->port){ - case IF_PORT_UNKNOWN: /* use auto here */ - dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ - netif_carrier_off(dev); + case IF_PORT_UNKNOWN: /* use auto here */ + dev->if_port = map->port; + /* we are going to change the media type, so the Link will + be temporary down and we need to reflect that here. When + the Link comes up again, it will be sensed by the sis_timer + procedure, which also does all the rest for us */ + netif_carrier_off(dev); - /* read current state */ - status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); + /* read current state */ + status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); - /* enable auto negotiation and reset the negotioation - (I dont really know what the auto negatiotiation reset - really means, but it sounds for me right to do one here)*/ - mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + /* enable auto negotiation and reset the negotioation + (I dont really know what the auto negatiotiation reset + really means, but it sounds for me right to do one here)*/ + mdio_write(dev, mii_phy->phy_addr, + MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); - break; + break; - case IF_PORT_10BASET: /* 10BaseT */ - dev->if_port = map->port; + case IF_PORT_10BASET: /* 10BaseT */ + dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ - netif_carrier_off(dev); + /* we are going to change the media type, so the Link will + be temporary down and we need to reflect that here. When + the Link comes up again, it will be sensed by the sis_timer + procedure, which also does all the rest for us */ + netif_carrier_off(dev); - /* set Speed to 10Mbps */ - /* read current state */ - status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); + /* set Speed to 10Mbps */ + /* read current state */ + status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); - /* disable auto negotiation and force 10MBit mode*/ - mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO)); - break; + /* disable auto negotiation and force 10MBit mode*/ + mdio_write(dev, mii_phy->phy_addr, + MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO)); + break; - case IF_PORT_100BASET: /* 100BaseT */ - case IF_PORT_100BASETX: /* 100BaseTx */ - dev->if_port = map->port; + case IF_PORT_100BASET: /* 100BaseT */ + case IF_PORT_100BASETX: /* 100BaseTx */ + dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ - netif_carrier_off(dev); + /* we are going to change the media type, so the Link will + be temporary down and we need to reflect that here. When + the Link comes up again, it will be sensed by the sis_timer + procedure, which also does all the rest for us */ + netif_carrier_off(dev); - /* set Speed to 100Mbps */ - /* disable auto negotiation and enable 100MBit Mode */ - status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); - mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED); + /* set Speed to 100Mbps */ + /* disable auto negotiation and enable 100MBit Mode */ + status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); + mdio_write(dev, mii_phy->phy_addr, + MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED); - break; + break; - case IF_PORT_10BASE2: /* 10Base2 */ - case IF_PORT_AUI: /* AUI */ - case IF_PORT_100BASEFX: /* 100BaseFx */ + case IF_PORT_10BASE2: /* 10Base2 */ + case IF_PORT_AUI: /* AUI */ + case IF_PORT_100BASEFX: /* 100BaseFx */ /* These Modes are not supported (are they?)*/ - printk(KERN_INFO "Not supported"); - return -EOPNOTSUPP; - break; + printk(KERN_INFO "Not supported"); + return -EOPNOTSUPP; + break; - default: - printk(KERN_INFO "Invalid"); - return -EINVAL; + default: + printk(KERN_INFO "Invalid"); + return -EINVAL; } } return 0; @@ -1713,12 +1815,15 @@ /** * sis900_compute_hashtable_index: - compute hashtable index * @addr: multicast address + * @revision: revision id of chip * * SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast * hash table, which makes this function a little bit different from other drivers + * SiS 900 B0 & 635 M/B uses the most significat 8 bits to index 256 bits + * multicast hash table. */ -static u16 sis900_compute_hashtable_index(u8 *addr) +static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision) { /* what is the correct value of the POLYNOMIAL ?? @@ -1741,51 +1846,63 @@ byte >>= 1; } } - /* leave 7 most siginifant bits */ - return ((int)(crc >> 25)); + + /* leave 8 or 7 most siginifant bits */ + if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV)) + return ((int)(crc >> 24)); + else + return ((int)(crc >> 25)); } /** * set_rx_mode: - Set SiS900 receive mode * @net_dev: the net device to be set * - * Set SiS900 receive mode for promiscuous, multicast, or broadcast mode. + * Set SiS900 receive mode for promiscuous, multicast, or broadcast mode. * And set the appropriate multicast filter. + * Multicast hash table changes from 128 to 256 bits for 635M/B & 900B0. */ static void set_rx_mode(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - u16 mc_filter[8]; /* 128 bits multicast hash table */ - int i; + struct sis900_private * sis_priv = net_dev->priv; + u16 mc_filter[16] = {0}; /* 256/128 bits multicast hash table */ + int i, table_entries; u32 rx_mode; + u8 revision; + + /* 635 Hash Table entires = 256(2^16) */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV)) + table_entries = 16; + else + table_entries = 8; if (net_dev->flags & IFF_PROMISC) { /* Accept any kinds of packets */ rx_mode = RFPromiscuous; - for (i = 0; i < 8; i++) + for (i = 0; i < table_entries; i++) mc_filter[i] = 0xffff; } else if ((net_dev->mc_count > multicast_filter_limit) || (net_dev->flags & IFF_ALLMULTI)) { /* too many multicast addresses or accept all multicast packet */ rx_mode = RFAAB | RFAAM; - for (i = 0; i < 8; i++) + for (i = 0; i < table_entries; i++) mc_filter[i] = 0xffff; } else { /* Accept Broadcast packet, destination address matchs our MAC address, use Receive Filter to reject unwanted MCAST packet */ struct dev_mc_list *mclist; rx_mode = RFAAB; - for (i = 0; i < 8; i++) - mc_filter[i]=0; for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count; i++, mclist = mclist->next) - set_bit(sis900_compute_hashtable_index(mclist->dmi_addr), + set_bit(sis900_compute_hashtable_index(mclist->dmi_addr, revision), mc_filter); } /* update Multicast Hash Table in Receive Filter */ - for (i = 0; i < 8; i++) { + for (i = 0; i < table_entries; i++) { /* why plus 0x04 ??, That makes the correct value for hash table. */ outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); outl(mc_filter[i], ioaddr + rfdr); @@ -1804,7 +1921,7 @@ outl(inl(ioaddr + rxcfg) | RxATX, ioaddr + rxcfg); /* restore cr */ outl(cr_saved, ioaddr + cr); - } + } return; } @@ -1815,13 +1932,16 @@ * * reset sis900 MAC and wait until finished * reset through command register + * change backoff algorithm for 900B0 & 635 M/B */ static void sis900_reset(struct net_device *net_dev) { + struct sis900_private * sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int i = 0; u32 status = TxRCMP | RxRCMP; + u8 revision; outl(0, ioaddr + ier); outl(0, ioaddr + imr); @@ -1834,7 +1954,11 @@ status ^= (inl(isr + ioaddr) & status); } - outl(PESEL, ioaddr + cfg); + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if( (revision == SIS635A_900_REV) || (revision == SIS900B_900_REV) ) + outl(PESEL | RND_CNT, ioaddr + cfg); + else + outl(PESEL, ioaddr + cfg); } /** @@ -1847,7 +1971,15 @@ static void __devexit sis900_remove(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - + struct sis900_private * sis_priv = net_dev->priv; + struct mii_phy *phy = NULL; + + while (sis_priv->first_mii) { + phy = sis_priv->first_mii; + sis_priv->first_mii = phy->next; + kfree(phy); + } + unregister_netdev(net_dev); kfree(net_dev); pci_release_regions(pci_dev); diff -u --recursive --new-file v2.4.3/linux/drivers/net/sis900.h linux/drivers/net/sis900.h --- v2.4.3/linux/drivers/net/sis900.h Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/sis900.h Wed Apr 11 21:17:59 2001 @@ -50,7 +50,10 @@ enum sis900_configuration_register_bits { DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080, SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010, - PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001 + PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001, + /* 635 & 900B Specific */ + RND_CNT = 0x00000400, FAIR_BACKOFF = 0x00000200, + EDB_MASTER_EN = 0x00002000 }; enum sis900_eeprom_access_reigster_bits { @@ -78,8 +81,10 @@ #define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */ #define TxMXDMA_shift 20 #define RxMXDMA_shift 20 -#define TX_DMA_BURST 0 -#define RX_DMA_BURST 0 + +enum sis900_tx_rx_dma{ + DMA_BURST_512 = 0, DMA_BURST_64 = 5 +}; /* transmit FIFO threshholds */ #define TX_FILL_THRESH 16 /* 1/4 FIFO size */ @@ -233,7 +238,8 @@ enum sis900_revision_id { SIS630A_900_REV = 0x80, SIS630E_900_REV = 0x81, - SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83 + SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83, + SIS635A_900_REV = 0x90, SIS900B_900_REV = 0x03 }; enum sis630_revision_id { @@ -263,8 +269,8 @@ /* PCI stuff, should be move to pic.h */ #define PCI_DEVICE_ID_SI_900 0x900 #define PCI_DEVICE_ID_SI_7016 0x7016 -#define SIS630_VENDOR_ID 0x0630 -#define SIS630_DEVICE_ID 0x1039 +#define SIS630_VENDOR_ID 0x1039 +#define SIS630_DEVICE_ID 0x0630 /* ioctl for accessing MII transceiver */ #define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.4.3/linux/drivers/net/starfire.c Fri Aug 11 15:57:58 2000 +++ linux/drivers/net/starfire.c Thu Apr 12 12:16:35 2001 @@ -97,9 +97,6 @@ /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include <linux/version.h> #include <linux/module.h> -#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) -#include <linux/modversions.h> -#endif #include <linux/kernel.h> #include <linux/string.h> diff -u --recursive --new-file v2.4.3/linux/drivers/net/stnic.c linux/drivers/net/stnic.c --- v2.4.3/linux/drivers/net/stnic.c Sat Dec 30 11:23:14 2000 +++ linux/drivers/net/stnic.c Wed Apr 11 21:24:52 2001 @@ -7,6 +7,7 @@ * Copyright (C) 1999 kaz Kojima */ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -21,6 +22,9 @@ #include <asm/io.h> #include <asm/hitachi_se.h> #include <asm/machvec.h> +#ifdef CONFIG_SH_STANDARD_BIOS +#include <asm/sh_bios.h> +#endif #include "8390.h" @@ -74,6 +78,7 @@ vword trash; trash = *(vword *) 0xa0000000; trash = *(vword *) 0xa0000000; + trash = *(vword *) 0xa0000000; } static inline byte @@ -112,10 +117,13 @@ /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init (dev)) { - printk ("Unable to get memory for dev->priv.\n"); + printk (KERN_EMERG "Unable to get memory for dev->priv.\n"); return -ENOMEM; } +#ifdef CONFIG_SH_STANDARD_BIOS + sh_bios_get_node_addr (stnic_eadr); +#endif for (i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = stnic_eadr[i]; @@ -129,7 +137,7 @@ share and the board will usually be enabled. */ i = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); if (i) { - printk (" unable to get IRQ %d.\n", dev->irq); + printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); unregister_netdev(dev); kfree(dev->priv); kfree(dev); @@ -157,7 +165,7 @@ stnic_open (struct net_device *dev) { #if 0 - printk ("stnic open\n"); + printk (KERN_DEBUG "stnic open\n"); #endif ei_open (dev); return 0; @@ -176,7 +184,7 @@ *(vhalf *) PA_83902_RST = 0; udelay (5); if (ei_debug > 1) - printk("8390 reset done (%ld).\n", jiffies); + printk (KERN_WARNING "8390 reset done (%ld).\n", jiffies); *(vhalf *) PA_83902_RST = ~0; udelay (5); } @@ -206,7 +214,7 @@ #endif if (ei_debug > 1) - printk ("ring %x status %02x next %02x count %04x.\n", + printk (KERN_DEBUG "ring %x status %02x next %02x count %04x.\n", ring_page, hdr->status, hdr->next, hdr->count); STNIC_WRITE (STNIC_CR, CR_RDMA | CR_PG0 | CR_STA); @@ -254,22 +262,14 @@ stnic_block_output (struct net_device *dev, int length, const unsigned char *buf, int output_page) { -#if 0 - STNIC_WRITE (PG0_RBCR0, 1); - STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA); -#else /* XXX: I don't know why but this works. -- gniibe */ - STNIC_WRITE (PG0_RBCR0, 0x42); - STNIC_WRITE (PG0_RBCR1, 0x00); - STNIC_WRITE (PG0_RBCR0, 0x42); - STNIC_WRITE (PG0_RBCR1, 0x00); + STNIC_WRITE (PG0_RBCR0, 1); /* Write non-zero value */ STNIC_WRITE (STNIC_CR, CR_RRD | CR_PG0 | CR_STA); STNIC_DELAY (); -#endif - STNIC_WRITE (PG0_RSAR0, 0); - STNIC_WRITE (PG0_RSAR1, output_page); STNIC_WRITE (PG0_RBCR0, length & 0xff); STNIC_WRITE (PG0_RBCR1, length >> 8); + STNIC_WRITE (PG0_RSAR0, 0); + STNIC_WRITE (PG0_RSAR1, output_page); STNIC_WRITE (STNIC_CR, CR_RWR | CR_PG0 | CR_STA); if (length & 1) diff -u --recursive --new-file v2.4.3/linux/drivers/net/sundance.c linux/drivers/net/sundance.c --- v2.4.3/linux/drivers/net/sundance.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/sundance.c Fri Apr 6 10:42:55 2001 @@ -1239,7 +1239,7 @@ struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (dev) { + if (dev) { unregister_netdev(dev); pci_release_regions(pdev); #ifndef USE_IO_OPS diff -u --recursive --new-file v2.4.3/linux/drivers/net/sungem.c linux/drivers/net/sungem.c --- v2.4.3/linux/drivers/net/sungem.c Sun Mar 25 18:14:21 2001 +++ linux/drivers/net/sungem.c Thu Apr 12 12:11:39 2001 @@ -1,4 +1,4 @@ -/* $Id: sungem.c,v 1.8 2001/03/22 22:48:51 davem Exp $ +/* $Id: sungem.c,v 1.11 2001/04/04 14:49:40 davem Exp $ * sungem.c: Sun GEM ethernet driver. * * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) @@ -159,13 +159,20 @@ dev->name); } - if (pcs_miistat & PCS_MIISTAT_LS) + if (pcs_miistat & PCS_MIISTAT_LS) { printk(KERN_INFO "%s: PCS link is now up.\n", dev->name); - else + } else { printk(KERN_INFO "%s: PCS link is now down.\n", dev->name); + /* If this happens and the link timer is not running, + * reset so we re-negotiate. + */ + if (!timer_pending(&gp->link_timer)) + return 1; + } + return 0; } @@ -441,7 +448,7 @@ struct gem_rxd *rxd = &gp->init_block->rxd[cluster_start]; for (;;) { - rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); rxd++; cluster_start = NEXT_RX(cluster_start); if (cluster_start == curr) @@ -491,19 +498,19 @@ if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; - new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC); if (new_skb == NULL) { drops++; goto drop_it; } pci_unmap_single(gp->pdev, dma_addr, - RX_BUF_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); gp->rx_skbs[entry] = new_skb; new_skb->dev = gp->dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev, new_skb->data, - RX_BUF_ALLOC_SIZE, + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE)); skb_reserve(new_skb, RX_OFFSET); @@ -527,6 +534,8 @@ skb = copy_skb; } + skb->csum = ((status & RXDCTRL_TCPCSUM) ^ 0xffff); + skb->ip_summed = CHECKSUM_HW; skb->protocol = eth_type_trans(skb, gp->dev); netif_rx(skb); @@ -548,8 +557,8 @@ static void gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *) dev_id; - struct gem *gp = (struct gem *) dev->priv; + struct net_device *dev = dev_id; + struct gem *gp = dev->priv; u32 gem_status = readl(gp->regs + GREG_STAT); spin_lock(&gp->lock); @@ -567,9 +576,36 @@ spin_unlock(&gp->lock); } +static void gem_tx_timeout(struct net_device *dev) +{ + struct gem *gp = dev->priv; + + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n", + dev->name, + readl(gp->regs + TXDMA_CFG), + readl(gp->regs + MAC_TXSTAT), + readl(gp->regs + MAC_TXCFG)); + printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n", + dev->name, + readl(gp->regs + RXDMA_CFG), + readl(gp->regs + MAC_RXSTAT), + readl(gp->regs + MAC_RXCFG)); + + spin_lock_irq(&gp->lock); + + gem_stop(gp, gp->regs); + gem_init_rings(gp, 1); + gem_init_hw(gp); + + spin_unlock_irq(&gp->lock); + + netif_wake_queue(dev); +} + static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct gem *gp = (struct gem *) dev->priv; + struct gem *gp = dev->priv; long len; int entry, avail; u32 mapping; @@ -602,6 +638,30 @@ return 0; } +/* Jumbo-grams don't seem to work :-( */ +#if 1 +#define MAX_MTU 1500 +#else +#define MAX_MTU 9000 +#endif + +static int gem_change_mtu(struct net_device *dev, int new_mtu) +{ + struct gem *gp = dev->priv; + + if (new_mtu < 0 || new_mtu > MAX_MTU) + return -EINVAL; + + spin_lock_irq(&gp->lock); + gem_stop(gp, gp->regs); + dev->mtu = new_mtu; + gem_init_rings(gp, 1); + gem_init_hw(gp); + spin_unlock_irq(&gp->lock); + + return 0; +} + #define STOP_TRIES 32 static void gem_stop(struct gem *gp, unsigned long regs) @@ -676,8 +736,29 @@ } else if (full_duplex) { val |= MAC_XIFCFG_FLED; } + + if (speed == 1000) + val |= (MAC_XIFCFG_GMII); + writel(val, gp->regs + MAC_XIFCFG); + /* If gigabit and half-duplex, enable carrier extension + * mode. Else, disable it. + */ + if (speed == 1000 && !full_duplex) { + val = readl(gp->regs + MAC_TXCFG); + writel(val | MAC_TXCFG_TCE, gp->regs + MAC_TXCFG); + + val = readl(gp->regs + MAC_RXCFG); + writel(val | MAC_RXCFG_RCE, gp->regs + MAC_RXCFG); + } else { + val = readl(gp->regs + MAC_TXCFG); + writel(val & ~MAC_TXCFG_TCE, gp->regs + MAC_TXCFG); + + val = readl(gp->regs + MAC_RXCFG); + writel(val & ~MAC_RXCFG_RCE, gp->regs + MAC_RXCFG); + } + if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes) { u32 pcs_lpa = readl(gp->regs + PCS_MIILP); @@ -689,10 +770,6 @@ val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE); writel(val, gp->regs + MAC_MCCFG); - /* XXX Set up PCS MII Control and Serialink Control - * XXX registers. - */ - if (!full_duplex) writel(512, gp->regs + MAC_STIME); else @@ -767,7 +844,16 @@ restart_timer = gem_mdio_link_not_up(gp); } } else { - /* XXX Code PCS support... XXX */ + u32 val = readl(gp->regs + PCS_MIISTAT); + + if (!(val & PCS_MIISTAT_LS)) + val = readl(gp->regs + PCS_MIISTAT); + + if ((val & PCS_MIISTAT_LS) == 0) { + restart_timer = 1; + } else { + gem_set_link_modes(gp); + } } if (restart_timer) { @@ -792,7 +878,7 @@ skb = gp->rx_skbs[i]; dma_addr = (u32) le64_to_cpu(rxd->buffer); pci_unmap_single(gp->pdev, dma_addr, - RX_BUF_ALLOC_SIZE, + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb); gp->rx_skbs[i] = NULL; @@ -834,7 +920,7 @@ struct sk_buff *skb; struct gem_rxd *rxd = &gb->rxd[i]; - skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags); if (!skb) { rxd->buffer = 0; rxd->status_word = 0; @@ -845,10 +931,10 @@ skb->dev = dev; skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); dma_addr = pci_map_single(gp->pdev, skb->data, - RX_BUF_ALLOC_SIZE, + RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); rxd->buffer = cpu_to_le64(dma_addr); - rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); skb_reserve(skb, RX_OFFSET); } @@ -863,15 +949,19 @@ static void gem_init_phy(struct gem *gp) { if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { + u32 val; + /* Init datapath mode register. */ if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { - writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); + val = PCS_DMODE_MGM; } else if (gp->phy_type == phy_serialink) { - writel(PCS_DMODE_SM, gp->regs + PCS_DMODE); + val = PCS_DMODE_SM | PCS_DMODE_GMOE; } else { - writel(PCS_DMODE_ESM, gp->regs + PCS_DMODE); + val = PCS_DMODE_ESM; } + + writel(val, gp->regs + PCS_DMODE); } if (gp->phy_type == phy_mii_mdio0 || @@ -899,7 +989,59 @@ val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); phy_write(gp, PHY_CTRL, val); } else { - /* XXX Implement me XXX */ + u32 val; + int limit; + + /* Reset PCS unit. */ + val = readl(gp->regs + PCS_MIICTRL); + val |= PCS_MIICTRL_RST; + writeb(val, gp->regs + PCS_MIICTRL); + + limit = 32; + while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) { + udelay(100); + if (limit-- <= 0) + break; + } + if (limit <= 0) + printk(KERN_WARNING "%s: PCS reset bit would not clear.\n", + gp->dev->name); + + /* Make sure PCS is disabled while changing advertisement + * configuration. + */ + val = readl(gp->regs + PCS_CFG); + val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO); + writel(val, gp->regs + PCS_CFG); + + /* Advertise all capabilities. */ + val = readl(gp->regs + PCS_MIIADV); + val |= (PCS_MIIADV_FD | PCS_MIIADV_HD | + PCS_MIIADV_SP | PCS_MIIADV_AP); + writel(val, gp->regs + PCS_MIIADV); + + /* Enable and restart auto-negotiation, disable wrapback/loopback, + * and re-enable PCS. + */ + val = readl(gp->regs + PCS_MIICTRL); + val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE); + val &= ~PCS_MIICTRL_WB; + writel(val, gp->regs + PCS_MIICTRL); + + val = readl(gp->regs + PCS_CFG); + val |= PCS_CFG_ENABLE; + writel(val, gp->regs + PCS_CFG); + + /* Make sure serialink loopback is off. The meaning + * of this bit is logically inverted based upon whether + * you are in Serialink or SERDES mode. + */ + val = readl(gp->regs + PCS_SCTRL); + if (gp->phy_type == phy_serialink) + val &= ~PCS_SCTRL_LOOP; + else + val |= PCS_SCTRL_LOOP; + writel(val, gp->regs + PCS_SCTRL); } } @@ -907,7 +1049,7 @@ { u32 val; - val = (TXDMA_CFG_BASE | (0x4ff << 10) | TXDMA_CFG_PMODE); + val = (TXDMA_CFG_BASE | (0x7ff << 10) | TXDMA_CFG_PMODE); writel(val, gp->regs + TXDMA_CFG); writel(0, gp->regs + TXDMA_DBHI); @@ -916,7 +1058,7 @@ writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512); writel(val, gp->regs + RXDMA_CFG); writel(0, gp->regs + RXDMA_DBHI); @@ -931,12 +1073,12 @@ writel(val, gp->regs + RXDMA_PTHRESH); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) - writel(((5 & RXDMA_BLANK_IPKTS) | - ((8 << 12) & RXDMA_BLANK_ITIME)), + writel(((6 & RXDMA_BLANK_IPKTS) | + ((4 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); else - writel(((5 & RXDMA_BLANK_IPKTS) | - ((4 << 12) & RXDMA_BLANK_ITIME)), + writel(((6 & RXDMA_BLANK_IPKTS) | + ((2 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); } @@ -955,7 +1097,7 @@ writel(0x04, gp->regs + MAC_IPG2); writel(0x40, gp->regs + MAC_STIME); writel(0x40, gp->regs + MAC_MINFSZ); - writel(0x5ee, gp->regs + MAC_MAXFSZ); + writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ); writel(0x07, gp->regs + MAC_PASIZE); writel(0x04, gp->regs + MAC_JAMSIZE); writel(0x10, gp->regs + MAC_ATTLIM); @@ -1097,7 +1239,7 @@ static int gem_open(struct net_device *dev) { - struct gem *gp = (struct gem *) dev->priv; + struct gem *gp = dev->priv; unsigned long regs = gp->regs; del_timer(&gp->link_timer); @@ -1117,6 +1259,9 @@ { struct gem *gp = dev->priv; + del_timer(&gp->link_timer); + gem_stop(gp, gp->regs); + gem_clean_rings(gp); free_irq(gp->pdev->irq, (void *)dev); return 0; } @@ -1263,13 +1408,17 @@ /* Determine initial PHY interface type guess. MDIO1 is the * external PHY and thus takes precedence over MDIO0. */ - if (mif_cfg & MIF_CFG_MDI1) + if (mif_cfg & MIF_CFG_MDI1) { gp->phy_type = phy_mii_mdio1; - else if (mif_cfg & MIF_CFG_MDI0) + mif_cfg |= MIF_CFG_PSELECT; + writel(mif_cfg, gp->regs + MIF_CFG); + } else if (mif_cfg & MIF_CFG_MDI0) { gp->phy_type = phy_mii_mdio0; - else + mif_cfg &= ~MIF_CFG_PSELECT; + writel(mif_cfg, gp->regs + MIF_CFG); + } else { gp->phy_type = phy_serialink; - + } if (gp->phy_type == phy_mii_mdio1 || gp->phy_type == phy_mii_mdio0) { int i; @@ -1279,6 +1428,13 @@ if (phy_read(gp, PHY_CTRL) != 0xffff) break; } + if (i == 32) { + if (pdev->device != PCI_DEVICE_ID_SUN_GEM) { + printk(KERN_ERR PFX "RIO MII phy will not respond.\n"); + return -1; + } + gp->phy_type = phy_serdes; + } } /* Fetch the FIFO configurations now too. */ @@ -1309,23 +1465,50 @@ if (gp->rx_fifo_sz <= (2 * 1024)) { gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; } else { - int off = ((gp->rx_fifo_sz * 3) / 4); - int on = off - (1 * 1024); + int off = (gp->rx_fifo_sz - (5 * 1024)); + int on = off - 1024; gp->rx_pause_off = off; gp->rx_pause_on = on; } { - u32 bifcfg = readl(gp->regs + GREG_BIFCFG); + u32 cfg = readl(gp->regs + GREG_BIFCFG); + + cfg |= GREG_BIFCFG_B64DIS; + writel(cfg, gp->regs + GREG_BIFCFG); - bifcfg |= GREG_BIFCFG_B64DIS; - writel(bifcfg, gp->regs + GREG_BIFCFG); + cfg = GREG_CFG_IBURST; + cfg |= ((31 << 1) & GREG_CFG_TXDMALIM); + cfg |= ((31 << 6) & GREG_CFG_RXDMALIM); + writel(cfg, gp->regs + GREG_CFG); } return 0; } +static void __devinit gem_get_device_address(struct gem *gp) +{ + struct net_device *dev = gp->dev; + struct pci_dev *pdev = gp->pdev; + +#ifdef __sparc__ + struct pcidev_cookie *pcp = pdev->sysdata; + int node = -1; + + if (pcp != NULL) { + node = pcp->prom_node; + if (prom_getproplen(node, "local-mac-address") == 6) + prom_getproperty(node, "local-mac-address", + dev->dev_addr, 6); + else + node = -1; + } + if (node == -1) + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); +#endif +} + static int __devinit gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1352,6 +1535,7 @@ printk(KERN_ERR PFX "Etherdev init failed, aborting.\n"); return -ENOMEM; } + SET_MODULE_OWNER(dev); if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) { printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, " @@ -1372,6 +1556,7 @@ gp->pdev = pdev; dev->base_addr = (long) pdev; + gp->dev = dev; spin_lock_init(&gp->lock); @@ -1402,9 +1587,7 @@ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", dev->name); -#ifdef __sparc__ - memcpy(dev->dev_addr, idprom->id_ethaddr, 6); -#endif + gem_get_device_address(gp); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], @@ -1415,13 +1598,15 @@ gp->link_timer.function = gem_link_timer; gp->link_timer.data = (unsigned long) gp; - gp->dev = dev; dev->open = gem_open; dev->stop = gem_close; dev->hard_start_xmit = gem_start_xmit; dev->get_stats = gem_get_stats; dev->set_multicast_list = gem_set_multicast; dev->do_ioctl = gem_ioctl; + dev->tx_timeout = gem_tx_timeout; + dev->watchdog_timeo = 5 * HZ; + dev->change_mtu = gem_change_mtu; dev->irq = pdev->irq; dev->dma = 0; diff -u --recursive --new-file v2.4.3/linux/drivers/net/sungem.h linux/drivers/net/sungem.h --- v2.4.3/linux/drivers/net/sungem.h Sun Mar 25 18:14:21 2001 +++ linux/drivers/net/sungem.h Thu Apr 12 12:11:39 2001 @@ -1,4 +1,4 @@ -/* $Id: sungem.h,v 1.5 2001/03/21 23:02:04 davem Exp $ +/* $Id: sungem.h,v 1.7 2001/04/04 14:49:40 davem Exp $ * sungem.h: Definitions for Sun GEM ethernet driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -727,7 +727,10 @@ #define PCS_DMODE_MGM 0x00000004 /* MII/GMII mode */ #define PCS_DMODE_GMOE 0x00000008 /* GMII Output Enable */ -/* Serialink Control Register. */ +/* Serialink Control Register. + * + * NOTE: When in SERDES mode, the loopback bit has inverse logic. + */ #define PCS_SCTRL_LOOP 0x00000001 /* Loopback enable */ #define PCS_SCTRL_ESCD 0x00000002 /* Enable sync char detection */ #define PCS_SCTRL_LOCK 0x00000004 /* Lock to reference clock */ @@ -837,8 +840,8 @@ #define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ #define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ -#define RXDCTRL_FRESH \ - ((((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ +#define RXDCTRL_FRESH(gp) \ + ((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ RXDCTRL_OWN) #define TX_RING_SIZE 128 @@ -897,7 +900,7 @@ (GP)->tx_old - (GP)->tx_new - 1) #define RX_OFFSET 2 -#define RX_BUF_ALLOC_SIZE (1546 + RX_OFFSET + 64) +#define RX_BUF_ALLOC_SIZE(gp) ((gp)->dev->mtu + 46 + RX_OFFSET + 64) #define RX_COPY_THRESHOLD 256 diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.4.3/linux/drivers/net/sunhme.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/sunhme.c Thu Apr 12 12:11:39 2001 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.105 2000/12/05 02:00:36 anton Exp $ +/* $Id: sunhme.c,v 1.115 2001/03/29 06:37:09 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -1277,12 +1277,23 @@ struct sk_buff *skb = hp->tx_skbs[i]; struct happy_meal_txd *txd; u32 dma_addr; + int frag; - txd = &hp->happy_block->happy_meal_txd[i]; - dma_addr = hme_read_desc32(hp, &txd->tx_addr); - hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); - dev_kfree_skb_any(skb); hp->tx_skbs[i] = NULL; + + for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { + txd = &hp->happy_block->happy_meal_txd[i]; + dma_addr = hme_read_desc32(hp, &txd->tx_addr); + hme_dma_unmap(hp, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TODEVICE); + + if (frag != skb_shinfo(skb)->nr_frags) + i++; + } + + dev_kfree_skb_any(skb); } } } @@ -1842,7 +1853,7 @@ if (status & GREG_STAT_NORXD) { /* This is harmless, it just means the system is - * quite loaded and the incomming packet rate was + * quite loaded and the incoming packet rate was * faster than the interrupt handler could keep up * with. */ @@ -1958,19 +1969,40 @@ TXD(("TX<")); while (elem != hp->tx_new) { struct sk_buff *skb; - u32 flags, dma_addr; + u32 flags, dma_addr, dma_len; + int frag; TXD(("[%d]", elem)); this = &txbase[elem]; flags = hme_read_desc32(hp, &this->tx_flags); if (flags & TXFLAG_OWN) break; - dma_addr = hme_read_desc32(hp, &this->tx_addr); skb = hp->tx_skbs[elem]; - hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); + if (skb_shinfo(skb)->nr_frags) { + int last; + + last = elem + skb_shinfo(skb)->nr_frags; + last &= (TX_RING_SIZE - 1); + flags = hme_read_desc32(hp, &txbase[last].tx_flags); + if (flags & TXFLAG_OWN) + break; + } hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes += skb->len; + for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { + dma_addr = hme_read_desc32(hp, &this->tx_addr); + dma_len = hme_read_desc32(hp, &this->tx_flags); + + dma_len &= TXFLAG_SIZE; + hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE); + + if (frag != skb_shinfo(skb)->nr_frags) { + elem = NEXT_TX(elem); + this = &txbase[elem]; + } + } + dev_kfree_skb_irq(skb); hp->net_stats.tx_packets++; @@ -2079,10 +2111,8 @@ } /* This card is _fucking_ hot... */ - if (!(csum ^ 0xffff)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; + skb->csum = (csum ^ 0xffff); + skb->ip_summed = CHECKSUM_HW; RXD(("len=%d csum=%4x]", len, csum)); skb->protocol = eth_type_trans(skb, dev); @@ -2104,7 +2134,7 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("happy_meal_interrupt: status=%08x ", happy_status)); @@ -2141,7 +2171,7 @@ for (i = 0; i < 4; i++) { struct net_device *dev = qp->happy_meals[i]; - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("quattro_interrupt: status=%08x ", happy_status)); @@ -2179,8 +2209,7 @@ static int happy_meal_open(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; - int res; + struct happy_meal *hp = dev->priv; HMD(("happy_meal_open: ")); @@ -2204,16 +2233,12 @@ } HMD(("to happy_meal_init\n")); - res = happy_meal_init(hp, 0); - if (!res) { - MOD_INC_USE_COUNT; - } - return res; + return happy_meal_init(hp, 0); } static int happy_meal_close(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; happy_meal_stop(hp, hp->gregs); happy_meal_clean_rings(hp); @@ -2226,9 +2251,8 @@ * time and never unregister. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) - free_irq(dev->irq, (void *)dev); + free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return 0; } @@ -2241,7 +2265,7 @@ #ifdef CONFIG_SBUS static void happy_meal_tx_timeout(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); tx_dump_log(); @@ -2256,22 +2280,79 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; - int len, entry; - u32 mapping; - - len = skb->len; - mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); + struct happy_meal *hp = dev->priv; + int entry; + u32 tx_flags; + + tx_flags = TXFLAG_OWN; + if (skb->ip_summed == CHECKSUM_HW) { + u32 csum_start_off, csum_stuff_off; + + csum_start_off = (u32) (skb->h.raw - skb->data); + csum_stuff_off = (u32) ((skb->h.raw + skb->csum) - skb->data); + + tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | + ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | + ((csum_stuff_off << 20) & TXFLAG_CSLOCATION)); + } spin_lock_irq(&hp->happy_lock); + if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + spin_unlock_irq(&hp->happy_lock); + return 1; + } + entry = hp->tx_new; SXD(("SX<l[%d]e[%d]>", len, entry)); hp->tx_skbs[entry] = skb; - hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], - (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)), - mapping); - hp->tx_new = NEXT_TX(entry); + + if (skb_shinfo(skb)->nr_frags == 0) { + u32 mapping, len; + + len = skb->len; + mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); + tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); + hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], + (tx_flags | (len & TXFLAG_SIZE)), + mapping); + entry = NEXT_TX(entry); + } else { + u32 first_len, first_mapping; + int frag, first_entry = entry; + + /* We must give this initial chunk to the device last. + * Otherwise we could race with the device. + */ + first_len = skb->len - skb->data_len; + first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE); + entry = NEXT_TX(entry); + + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + u32 len, mapping, this_txflags; + + len = this_frag->size; + mapping = hme_dma_map(hp, + ((void *) page_address(this_frag->page) + + this_frag->page_offset), + len, DMA_TODEVICE); + this_txflags = tx_flags; + if (frag == skb_shinfo(skb)->nr_frags - 1) + this_txflags |= TXFLAG_EOP; + hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], + (this_txflags | (len & TXFLAG_SIZE)), + mapping); + entry = NEXT_TX(entry); + } + hme_write_txd(hp, &hp->happy_block->happy_meal_txd[first_entry], + (tx_flags | TXFLAG_SOP | (first_len & TXFLAG_SIZE)), + first_mapping); + } + + hp->tx_new = entry; + if (TX_BUFFS_AVAIL(hp) <= 0) netif_stop_queue(dev); @@ -2288,7 +2369,7 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; happy_meal_get_counters(hp, hp->bigmacregs); return &hp->net_stats; @@ -2296,7 +2377,7 @@ static void happy_meal_set_multicast(struct net_device *dev) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; unsigned long bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; @@ -2355,7 +2436,7 @@ static int happy_meal_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct happy_meal *hp = dev->priv; struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data; struct ethtool_cmd ecmd; @@ -2480,27 +2561,23 @@ struct sbus_bus *sbus; struct sbus_dev *sdev; struct quattro *qp; + int i; if (qfe_sbus_list == NULL) goto found; for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - for (sdev = qp->quattro_dev; - sdev != NULL; - sdev = sdev->next) { + for (i = 0, sdev = qp->quattro_dev; + (sdev != NULL) && (i < 4); + sdev = sdev->next, i++) { if (sdev == goal_sdev) return qp; } } for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { - if (sdev->child != NULL) { - struct sbus_dev *p; - - for (p = sdev->child; p != NULL; p = p->next) - if (p == goal_sdev) - goto found; - } + if (sdev == goal_sdev) + goto found; } } @@ -2578,12 +2655,11 @@ #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __init happy_meal_sbus_init(struct net_device *dev, - struct sbus_dev *sdev, - int is_qfe) +static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) { struct quattro *qp = NULL; struct happy_meal *hp; + struct net_device *dev; int i, qfe_slot = -1; if (is_qfe) { @@ -2596,13 +2672,12 @@ if (qfe_slot == 4) return -ENODEV; } - if (dev == NULL) { - dev = init_etherdev(0, sizeof(struct happy_meal)); - } else { - dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - } + + dev = init_etherdev(NULL, sizeof(struct happy_meal)); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); + if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2637,7 +2712,7 @@ dev->dev_addr[i], i == 5 ? ' ' : ':'); printk("\n"); - hp = (struct happy_meal *) dev->priv; + hp = dev->priv; memset(hp, 0, sizeof(*hp)); hp->happy_dev = sdev; @@ -2733,6 +2808,9 @@ dev->watchdog_timeo = 5*HZ; dev->do_ioctl = &happy_meal_ioctl; + /* Happy Meal can do it all... */ + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->irq = sdev->irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) @@ -2766,7 +2844,7 @@ #endif #ifdef CONFIG_PCI -static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pdev) +static int __init happy_meal_pci_init(struct pci_dev *pdev) { struct quattro *qp = NULL; #ifdef __sparc__ @@ -2774,6 +2852,7 @@ int node; #endif struct happy_meal *hp; + struct net_device *dev; unsigned long hpreg_base; int i, qfe_slot = -1; char prom_name[64]; @@ -2803,13 +2882,12 @@ if (qfe_slot == 4) return -ENODEV; } - if (dev == NULL) { - dev = init_etherdev(0, sizeof(struct happy_meal)); - } else { - dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - } + + dev = init_etherdev(NULL, sizeof(struct happy_meal)); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); + if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2856,7 +2934,10 @@ printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); return -ENODEV; } - hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000); + if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) { + printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); + return -ENODEV; + } for (i = 0; i < 6; i++) { if (macaddr[i] != 0) @@ -2941,6 +3022,9 @@ dev->irq = pdev->irq; dev->dma = 0; + /* Happy Meal can do it all... */ + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up PCI register/dma accessors. */ hp->read_desc32 = pci_hme_read_desc32; @@ -2972,25 +3056,29 @@ #endif #ifdef CONFIG_SBUS -static int __init happy_meal_sbus_probe(struct net_device *dev) +static int __init happy_meal_sbus_probe(void) { struct sbus_bus *sbus; struct sbus_dev *sdev; int cards = 0; + char model[128]; for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { char *name = sdev->prom_name; - if (cards) - dev = NULL; if (!strcmp(name, "SUNW,hme")) { cards++; - happy_meal_sbus_init(dev, sdev, 0); + prom_getstring(sdev->prom_node, "model", + model, sizeof(model)); + if (!strcmp(model, "SUNW,sbus-qfe")) + happy_meal_sbus_init(sdev, 1); + else + happy_meal_sbus_init(sdev, 0); } else if (!strcmp(name, "qfe") || !strcmp(name, "SUNW,qfe")) { cards++; - happy_meal_sbus_init(dev, sdev, 1); + happy_meal_sbus_init(sdev, 1); } } } @@ -3001,7 +3089,7 @@ #endif #ifdef CONFIG_PCI -static int __init happy_meal_pci_probe(struct net_device *dev) +static int __init happy_meal_pci_probe(void) { struct pci_dev *pdev = NULL; int cards = 0; @@ -3010,10 +3098,8 @@ PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) { if (pci_enable_device(pdev)) continue; - if (cards) - dev = NULL; cards++; - happy_meal_pci_init(dev, pdev); + happy_meal_pci_init(pdev); } return cards; } @@ -3021,7 +3107,6 @@ static int __init happy_meal_probe(void) { - struct net_device *dev = NULL; static int called = 0; int cards; @@ -3033,12 +3118,10 @@ cards = 0; #ifdef CONFIG_SBUS - cards += happy_meal_sbus_probe(dev); - if (cards != 0) - dev = NULL; + cards += happy_meal_sbus_probe(); #endif #ifdef CONFIG_PCI - cards += happy_meal_pci_probe(dev); + cards += happy_meal_pci_probe(); #endif if (!cards) return -ENODEV; @@ -3048,12 +3131,23 @@ static void __exit happy_meal_cleanup_module(void) { +#ifdef CONFIG_SBUS + struct quattro *last_seen_qfe = NULL; +#endif + while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; struct happy_meal *next = root_happy_dev->next_module; #ifdef CONFIG_SBUS if (!(hp->happy_flags & HFLAG_PCI)) { + if (hp->happy_flags & HFLAG_QUATTRO) { + if (hp->qfe_parent != last_seen_qfe) { + free_irq(hp->dev->irq, hp->qfe_parent); + last_seen_qfe = hp->qfe_parent; + } + } + sbus_iounmap(hp->gregs, GREG_REG_SIZE); sbus_iounmap(hp->etxregs, ETX_REG_SIZE); sbus_iounmap(hp->erxregs, ERX_REG_SIZE); @@ -3071,6 +3165,7 @@ PAGE_SIZE, hp->happy_block, hp->hblock_dvma); + iounmap((void *)hp->gregs); } #endif unregister_netdev(hp->dev); diff -u --recursive --new-file v2.4.3/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.4.3/linux/drivers/net/sunhme.h Mon Dec 11 13:01:05 2000 +++ linux/drivers/net/sunhme.h Thu Apr 12 12:11:39 2001 @@ -1,4 +1,4 @@ -/* $Id: sunhme.h,v 1.31 2000/11/12 10:23:30 davem Exp $ +/* $Id: sunhme.h,v 1.32 2000/12/13 18:31:47 davem Exp $ * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver. * Also known as the "Happy Meal". * @@ -151,7 +151,8 @@ #define ERX_CFG_SIZE128 0x00000400 /* Receive ring size == 128 */ #define ERX_CFG_SIZE256 0x00000600 /* Receive ring size == 256 */ #define ERX_CFG_RESV3 0x0000f800 /* Unused... */ -#define ERX_CFG_CSUMSTART 0x007f0000 /* Offset of checksum start */ +#define ERX_CFG_CSUMSTART 0x007f0000 /* Offset of checksum start, + * in halfwords. */ /* I'd like a Big Mac, small fries, small coke, and SparcLinux please. */ #define BMAC_XIFCFG 0x0000UL /* XIF config register */ @@ -445,14 +446,31 @@ #define TX_RING_SIZE 32 /* Must be >16 and <255, multiple of 16 */ #define RX_RING_SIZE 32 /* see ERX_CFG_SIZE* for possible values */ +#if (TX_RING_SIZE < 16 || TX_RING_SIZE > 256 || (TX_RING_SIZE % 16) != 0) +#error TX_RING_SIZE holds illegal value +#endif + #define TX_RING_MAXSIZE 256 #define RX_RING_MAXSIZE 256 -/* 34 byte offset for checksum computation. This works because ip_input() will clear out - * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are - * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr) - */ -#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|(0x22<<16)) +/* We use a 14 byte offset for checksum computation. */ +#if (RX_RING_SIZE == 32) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|((14/2)<<16)) +#else +#if (RX_RING_SIZE == 64) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE64|((14/2)<<16)) +#else +#if (RX_RING_SIZE == 128) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE128|((14/2)<<16)) +#else +#if (RX_RING_SIZE == 256) +#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE256|((14/2)<<16)) +#else +#error RX_RING_SIZE holds illegal value +#endif +#endif +#endif +#endif #define NEXT_RX(num) (((num) + 1) & (RX_RING_SIZE - 1)) #define NEXT_TX(num) (((num) + 1) & (TX_RING_SIZE - 1)) diff -u --recursive --new-file v2.4.3/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c --- v2.4.3/linux/drivers/net/tokenring/smctr.c Tue Mar 20 12:05:00 2001 +++ linux/drivers/net/tokenring/smctr.c Fri Apr 13 20:26:07 2001 @@ -5269,7 +5269,7 @@ return (POSITIVE_ACK); } -/* Reset the ring speed to the oposite of what it was. This auto-pilot +/* Reset the ring speed to the opposite of what it was. This auto-pilot * mode requires a complete reset and re-init of the adapter. */ static int smctr_set_ring_speed(struct net_device *dev) diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.4.3/linux/drivers/net/tulip/21142.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/tulip/21142.c Tue Apr 3 10:19:43 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/21142.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -107,16 +108,17 @@ dev->if_port = 0; tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; + if (tp->chip_id == PNIC2) { + tp->csr6 = 0x01000000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0); + return; + } if (tulip_debug > 1) printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n", dev->name, csr14); outl(0x0001, ioaddr + CSR13); udelay(100); outl(csr14, ioaddr + CSR14); - if (tp->chip_id == PNIC2) - tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - else - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? FullDuplex : 0); tulip_outl_csr(tp, tp->csr6, CSR6); if (tp->mtable && tp->mtable->csr15dir) { outl(tp->mtable->csr15dir, ioaddr + CSR15); diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog --- v2.4.3/linux/drivers/net/tulip/ChangeLog Fri Mar 2 11:02:14 2001 +++ linux/drivers/net/tulip/ChangeLog Tue Apr 3 10:19:43 2001 @@ -1,3 +1,80 @@ +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c: Remove code that existed when one or more of + the following defines existed. These defines were never used + by normal users in practice: TULIP_FULL_DUPLEX, + TULIP_DEFAULT_MEDIA, and TULIP_NO_MEDIA_SWITCH. + + * tulip.h, eeprom.c: Move EE_* constants from tulip.h to eeprom.c. + * tulip.h, media.c: Move MDIO_* constants from tulip.h to media.c. + + * media.c: Add barrier() to mdio_read/write's PNIC status check + loops. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + Merged from Becker's tulip.c 0.92t: + + * tulip.h: Add MEDIA_MASK constant for bounding medianame[] + array lookups. + * eeprom.c, media.c, timer.c, tulip_core.c: Use it. + + * media.c, tulip_core.c: mdio_{read,write} cleanup. Since this + is called [pretty much] directly from ioctl, we mask + read/write arguments to limit the values passed. + Added mii_lock. Added comet_miireg2offset and better + Comet-specific mdio_read/write code. Pay closer attention + to the bits we set in ioctl. Remove spinlocks from ioctl, + they are in mdio_read/write now. Use mask to limit + phy number in tulip_init_one's MII scan. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + Merged from Becker's tulip.c 0.92t: + + * 21142.c, tulip_core.c: PNIC2 MAC address and NWay fixes. + * tulip.h: Add FullDuplex constant, used in above change. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * timer.c: Do not call netif_carrier_{on,off}, it is not used in + the main tree. Leave code in, disabled, as markers for future + carrier notification. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + Merged from Becker's tulip.c 0.92t, except for the tulip.h + whitespace cleanup: + + * interrupt.c: If Rx stops, make sure to update the + multicast filter before restarting. + * tulip.h: Add COMET_MAC_ADDR feature flag, clean up flags. + Add Accept* Rx mode bit constants. + Add mc_filter[] to driver private struct. + * tulip_core.c: Add new Comet PCI id 0x1113:0x9511. + Add COMET_MAC_ADDR feature flag to comet entry in board info array. + Prefer to test COMET_MAC_ADDR flag to testing chip_id for COMET, + when dealing with the Comet's MAC address. + Enable Tx underrun recovery for Comet chips. + Use new Accept* constants in set_rx_mode. + Prefer COMET_MAC_ADDR flag test to chip_id test in set_rx_mode. + Store built mc_filter for later use in intr handler by Comets. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * tulip_core.c: Use tp->cur_tx when building the + setup frame, instead of assuming that the setup + frame is always built in slot zero. This case is + hit during PM resume. + +2001-04-03 Jeff Garzik <jgarzik@mandrakesoft.com> + + * *.c: Update file headers (copyright, urls, etc.) + * Makefile: re-order to that chip-specific modules on own line + * eeprom.c: BSS/zero-init cleanup (Andrey Panin) + * tulip_core.c: merge medianame[] update from tulip.c. + Additional arch-specific rx_copybreak, csr0 values. (various) + 2001-02-20 Jeff Garzik <jgarzik@mandrakesoft.com> * media.c (tulip_select_media): No need to initialize diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/Makefile linux/drivers/net/tulip/Makefile --- v2.4.3/linux/drivers/net/tulip/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/tulip/Makefile Tue Apr 3 10:19:43 2001 @@ -9,7 +9,9 @@ O_TARGET := tulip.o -obj-y := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o +obj-y := eeprom.o interrupt.o media.o \ + timer.o tulip_core.o \ + 21142.o pnic.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c --- v2.4.3/linux/drivers/net/tulip/eeprom.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/tulip/eeprom.c Tue Apr 3 10:19:43 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/eeprom.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -77,9 +78,9 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) { /* The last media info list parsed, for multiport boards. */ - static struct mediatable *last_mediatable = NULL; - static unsigned char *last_ee_data = NULL; - static int controller_index = 0; + static struct mediatable *last_mediatable; + static unsigned char *last_ee_data; + static int controller_index; struct tulip_private *tp = (struct tulip_private *)dev->priv; unsigned char *ee_data = tp->eeprom; int i; @@ -143,9 +144,10 @@ printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", dev->name, media, - media & 0x0800 ? "Autosense" : medianame[media & 15]); + media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { - unsigned char media_code = *p++; + unsigned char media_block = *p++; + int media_code = media_block & MEDIA_MASK; if (media_code & 0x40) p += 6; printk(KERN_INFO "%s: 21041 media #%d, %s.\n", @@ -182,7 +184,7 @@ mtable->csr15dir = mtable->csr15val = 0; printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & 15]); + media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; @@ -216,7 +218,7 @@ new_advertise |= get_u16(&p[7+gpr_len+reset_len]); } else { mtable->has_nonmii = 1; - leaf->media = p[2] & 0x0f; + leaf->media = p[2] & MEDIA_MASK; /* Davicom's media number for 100BaseTX is strange */ if (tp->chip_id == DM910X && leaf->media == 1) leaf->media = 3; @@ -261,6 +263,23 @@ } } /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_READ_CMD (6) /* Note: this routine returns extra data bits for size detection. */ int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.4.3/linux/drivers/net/tulip/interrupt.c Fri Mar 2 11:02:14 2001 +++ linux/drivers/net/tulip/interrupt.c Tue Apr 3 10:19:43 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/interrupt.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -299,6 +300,12 @@ /* Restart the transmit process. */ tulip_restart_rxtx(tp, tp->csr6); outl(0, ioaddr + CSR1); + } + if (csr5 & (RxDied | RxNoBuf)) { + if (tp->flags & COMET_MAC_ADDR) { + outl(tp->mc_filter[0], ioaddr + 0xAC); + outl(tp->mc_filter[1], ioaddr + 0xB0); + } } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_errors++; diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.4.3/linux/drivers/net/tulip/media.c Fri Mar 2 11:02:14 2001 +++ linux/drivers/net/tulip/media.c Tue Apr 3 10:19:43 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/media.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -22,6 +23,25 @@ 10base2(!) packets trigger a full-duplex-request interrupt. */ #define FULL_DUPLEX_MAGIC 0x6969 +/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +static const unsigned char comet_miireg2offset[32] = { + 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8, 0xCC, 0, 0,0,0,0, 0,0,0,0, + 0,0xD0,0,0, 0,0,0,0, 0,0,0,0, 0, 0xD4, 0xD8, 0xDC, }; + /* MII transceiver control section. Read and write the MII registers using software-generated serial @@ -32,32 +52,34 @@ { struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location; int retval = 0; long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; + unsigned long flags; + + if (location & ~0x1f) + return 0xffff; + + if (tp->chip_id == COMET && phy_id == 30) { + if (comet_miireg2offset[location]) + return inl(ioaddr + comet_miireg2offset[location]); + return 0xffff; + } + spin_lock_irqsave(&tp->mii_lock, flags); if (tp->chip_id == LC82C168) { int i = 1000; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); inl(ioaddr + 0xA0); inl(ioaddr + 0xA0); - while (--i > 0) + while (--i > 0) { + barrier(); if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xffff; - return 0xffff; - } - - if (tp->chip_id == COMET) { - if (phy_id == 1) { - if (location < 7) - return inl(ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - return inl(ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - return inl(ioaddr + 0xD4 + ((location-29)<<2)); + break; } - return 0xffff; + spin_unlock_irqrestore(&tp->mii_lock, flags); + return retval & 0xffff; } /* Establish sync by sending at least 32 logic ones. */ @@ -84,36 +106,39 @@ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + + spin_unlock_irqrestore(&tp->mii_lock, flags); return (retval>>1) & 0xffff; } -void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value) +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff); long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; + unsigned long flags; + + if (location & ~0x1f) + return; + + if (tp->chip_id == COMET && phy_id == 30) { + if (comet_miireg2offset[location]) + outl(val, ioaddr + comet_miireg2offset[location]); + return; + } + spin_lock_irqsave(&tp->mii_lock, flags); if (tp->chip_id == LC82C168) { int i = 1000; outl(cmd, ioaddr + 0xA0); - do + do { + barrier(); if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) break; - while (--i > 0); - return; - } - - if (tp->chip_id == COMET) { - if (phy_id != 1) - return; - if (location < 7) - outl(value, ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - outl(value, ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + } while (--i > 0); + spin_unlock_irqrestore(&tp->mii_lock, flags); return; } @@ -139,6 +164,8 @@ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + + spin_unlock_irqrestore(&tp->mii_lock, flags); } @@ -172,7 +199,7 @@ for (i = 0; i < 5; i++) setup[i] = get_u16(&p[i*2 + 1]); - dev->if_port = p[0] & 15; + dev->if_port = p[0] & MEDIA_MASK; if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) tp->full_duplex = 1; diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.4.3/linux/drivers/net/tulip/pnic.c Fri Mar 2 11:02:14 2001 +++ linux/drivers/net/tulip/pnic.c Tue Apr 3 10:19:43 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/pnic.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c --- v2.4.3/linux/drivers/net/tulip/timer.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/tulip/timer.c Tue Apr 3 10:19:43 2001 @@ -2,14 +2,15 @@ drivers/net/tulip/timer.c Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please refer to Documentation/networking/tulip.txt for more - information on this driver. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -133,13 +134,13 @@ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { if (tulip_debug > 2) printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, - medianame[mleaf->media]); + medianame[mleaf->media & MEDIA_MASK]); if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ goto actually_mii; - netif_carrier_on(dev); + /* netif_carrier_on(dev); */ break; } - netif_carrier_off(dev); + /* netif_carrier_off(dev); */ if (tp->medialock) break; select_next_media: @@ -152,9 +153,9 @@ goto select_next_media; /* Skip FD entries. */ if (tulip_debug > 1) printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & 15], - medianame[tp->mtable->mleaf[tp->cur_index].media]); + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & MEDIA_MASK], + medianame[tp->mtable->mleaf[tp->cur_index].media]); tulip_select_media(dev, 0); /* Restart the transmit process. */ tulip_restart_rxtx(tp, tp->csr6); @@ -164,9 +165,9 @@ case 1: case 3: /* 21140, 21142 MII */ actually_mii: if (tulip_check_duplex(dev) < 0) - netif_carrier_off(dev); + { /* netif_carrier_off(dev); */ } else - netif_carrier_on(dev); + { /* netif_carrier_on(dev); */ } next_tick = 60*HZ; break; case 2: /* 21142 serial block has no link beat. */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.4.3/linux/drivers/net/tulip/tulip.h Tue Mar 6 22:44:16 2001 +++ linux/drivers/net/tulip/tulip.h Tue Apr 3 10:19:43 2001 @@ -1,12 +1,16 @@ /* drivers/net/tulip/tulip.h - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ + */ #ifndef __NET_TULIP_H__ @@ -46,17 +50,18 @@ enum tbl_flag { - HAS_MII = 1, - HAS_MEDIA_TABLE = 2, - CSR12_IN_SROM = 4, - ALWAYS_CHECK_MII = 8, - HAS_ACPI = 0x10, - MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ - HAS_PNICNWAY = 0x80, - HAS_NWAY = 0x40, /* Uses internal NWay xcvr. */ - HAS_INTR_MITIGATION = 0x100, - IS_ASIX = 0x200, - HAS_8023X = 0x400, + HAS_MII = 0x0001, + HAS_MEDIA_TABLE = 0x0002, + CSR12_IN_SROM = 0x0004, + ALWAYS_CHECK_MII = 0x0008, + HAS_ACPI = 0x0010, + MC_HASH_ONLY = 0x0020, /* Hash-only multicast filter. */ + HAS_PNICNWAY = 0x0080, + HAS_NWAY = 0x0040, /* Uses internal NWay xcvr. */ + HAS_INTR_MITIGATION = 0x0100, + IS_ASIX = 0x0200, + HAS_8023X = 0x0400, + COMET_MAC_ADDR = 0x0800, }; @@ -139,6 +144,15 @@ }; +enum tulip_rx_modes { + FullDuplex = 0x0200, + AcceptBroadcast = 0x0100, + AcceptAllMulticast = 0x0080, + AcceptAllPhys = 0x0040, + AcceptRunt = 0x0008, +}; + + /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; @@ -236,6 +250,7 @@ #define TX_RING_SIZE 16 #define RX_RING_SIZE 32 +#define MEDIA_MASK 31 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -251,45 +266,11 @@ #define DESC_RING_WRAP 0x02000000 -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ -#define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. - We add a bus turn-around to insure that this remains true. */ -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_READ_CMD (6) - #define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues or future 66Mhz PCI. */ -#define mdio_delay() inl(mdio_addr) - -/* Read and write the MII registers using software-generated serial - MDIO protocol. It is just different enough from the EEPROM protocol - to not share code. The maxium data clock rate is 2.5 Mhz. */ -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 - - #define RUN_AT(x) (jiffies + (x)) - #if defined(__i386__) /* AKA get_unaligned() */ #define get_u16(ptr) (*(u16 *)(ptr)) #else @@ -346,7 +327,9 @@ int flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ + u32 mc_filter[2]; spinlock_t lock; + spinlock_t mii_lock; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ diff -u --recursive --new-file v2.4.3/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.3/linux/drivers/net/tulip/tulip_core.c Fri Mar 2 11:02:14 2001 +++ linux/drivers/net/tulip/tulip_core.c Tue Apr 3 10:19:43 2001 @@ -2,20 +2,15 @@ /* Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Please read Documentation/networking/tulip.txt for more - information. - - For this specific driver variant please use linux-kernel for - bug reports. - - Additional information available at - http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ */ @@ -28,7 +23,7 @@ #include <asm/unaligned.h> static char version[] __devinitdata = - "Linux Tulip driver version 0.9.14 (February 20, 2001)\n"; + "Linux Tulip driver version 0.9.14d (April 3, 2001)\n"; /* A few user-configurable values. */ @@ -43,16 +38,19 @@ static int mtu[MAX_UNITS]; /* Jumbo MTU for interfaces. */ /* The possible media types that can be set in options[] are: */ -const char * const medianame[] = { +const char * const medianame[32] = { "10baseT", "10base2", "AUI", "100baseTx", - "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", - "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", - "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", + "10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx", + "100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4", + "MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19", + "","","","", "","","","", "","","","Transceiver reset", }; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc_) || defined(__ia64__) + || defined(__sparc_) || defined(__ia64__) \ + || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else static int rx_copybreak = 100; @@ -81,7 +79,7 @@ * any more than that. */ static int csr0 = 0x01A00000 | 0x9000; -#elif defined(__arm__) +#elif defined(__arm__) || defined(__sh__) static int csr0 = 0x01A00000 | 0x4800; #else #warning Processor architecture undefined! @@ -162,7 +160,7 @@ /* COMET */ { "ADMtek Comet", 256, 0x0001abef, - MC_HASH_ONLY, comet_timer }, + MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer }, /* COMPEX9881 */ { "Compex 9881 PMAC", 128, 0x0001ebef, @@ -204,14 +202,15 @@ { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, {0, } }; MODULE_DEVICE_TABLE(pci, tulip_pci_tbl); /* A full-duplex map for media types. */ -const char tulip_media_cap[] = -{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +const char tulip_media_cap[32] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20, 28,31,0,0, }; u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ @@ -286,6 +285,14 @@ if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); + if (tp->chip_id == PNIC2) { + u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0); + /* This address setting does not appear to impact chip operation?? */ + outl((dev->dev_addr[5]<<8) + dev->dev_addr[4] + + (dev->dev_addr[3]<<24) + (dev->dev_addr[2]<<16), + ioaddr + 0xB0); + outl(addr_high + (addr_high<<16), ioaddr + 0xB8); + } if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); @@ -294,7 +301,7 @@ outl(addr_low, ioaddr + CSR14); outl(1, ioaddr + CSR13); outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { + } else if (tp->flags & COMET_MAC_ADDR) { outl(addr_low, ioaddr + 0xA4); outl(addr_high, ioaddr + 0xA8); outl(0, ioaddr + 0xAC); @@ -316,13 +323,13 @@ mapping = pci_map_single(tp->pdev, tp->setup_frame, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); - tp->tx_buffers[0].skb = NULL; - tp->tx_buffers[0].mapping = mapping; + tp->tx_buffers[tp->cur_tx].skb = NULL; + tp->tx_buffers[tp->cur_tx].mapping = mapping; /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); - tp->tx_ring[0].buffer1 = cpu_to_le32(mapping); - tp->tx_ring[0].status = cpu_to_le32(DescOwned); + tp->tx_ring[tp->cur_tx].length = cpu_to_le32(0x08000000 | 192); + tp->tx_ring[tp->cur_tx].buffer1 = cpu_to_le32(mapping); + tp->tx_ring[tp->cur_tx].status = cpu_to_le32(DescOwned); tp->cur_tx++; } @@ -349,7 +356,7 @@ } } if ((tp->mtable->defaultmedia & 0x0800) == 0) { - int looking_for = tp->mtable->defaultmedia & 15; + int looking_for = tp->mtable->defaultmedia & MEDIA_MASK; for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == looking_for) { printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", @@ -418,7 +425,9 @@ outl(0x0000, ioaddr + CSR14); outl(0x0008, ioaddr + CSR15); } else if (tp->chip_id == COMET) { - dev->if_port = 0; + /* Enable automatic Tx underrun recovery. */ + outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88); + dev->if_port = tp->mii_cnt ? 11 : 0; tp->csr6 = 0x00040000; } else if (tp->chip_id == AX88140) { tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; @@ -789,16 +798,16 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + u16 *data = (u16 *) & rq->ifr_data; int phy = tp->phys[0] & 0x1f; - long flags; + unsigned int regnum = data[1]; - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + switch (cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ if (tp->mii_cnt) data[0] = phy; else if (tp->flags & HAS_NWAY) @@ -807,42 +816,64 @@ data[0] = 1; else return -ENODEV; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY)) { - int csr12 = inl(ioaddr + CSR12); - int csr14 = inl(ioaddr + CSR14); - switch (data[1]) { - case 0: { - data[3] = (csr14<<5) & 0x1000; - break; } + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { + int csr12 = inl (ioaddr + CSR12); + int csr14 = inl (ioaddr + CSR14); + switch (regnum) { + case 0: + data[3] = (csr14 << 5) & 0x1000; + break; case 1: - data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) - + (csr12&0x06 ? 0x04 : 0); + data[3] = + 0x7848 + + ((csr12 & 0x7000) == 0x5000 ? 0x20 : 0) + + (csr12 & 0x06 ? 0x04 : 0); break; - case 4: { - data[3] = ((csr14>>9)&0x07C0) + - ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; + case 4: + data[3] = + ((csr14 >> 9) & 0x07C0) + + ((inl (ioaddr + CSR6) >> 3) & 0x0040) + + ((csr14 >> 1) & 0x20) + 1; + break; + case 5: + data[3] = csr12 >> 16; + break; + default: + data[3] = 0; break; - } - case 5: data[3] = csr12 >> 16; break; - default: data[3] = 0; break; } } else { - spin_lock_irqsave (&tp->lock, flags); - data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); - spin_unlock_irqrestore (&tp->lock, flags); + data[3] = tulip_mdio_read (dev, data[0] & 0x1f, regnum); } return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + if (!capable (CAP_NET_ADMIN)) return -EPERM; - if (data[0] == 32 && (tp->flags & HAS_NWAY)) { - if (data[1] == 5) + if (regnum & ~0x1f) + return -EINVAL; + if (data[0] == phy) { + u16 value = data[2]; + switch (regnum) { + case 0: /* Check for autonegotiation on or reset. */ + tp->full_duplex_lock = (value & 0x9000) ? 0 : 1; + if (tp->full_duplex_lock) + tp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: tp->to_advertise = data[2]; + break; + } + } + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { + u16 value = data[2]; + if (regnum == 0) { + if ((value & 0x1200) == 0x1200) + t21142_start_nway (dev); + } else if (regnum == 4) + tp->to_advertise = value; } else { - spin_lock_irqsave (&tp->lock, flags); - tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - spin_unlock_irqrestore(&tp->lock, flags); + tulip_mdio_write (dev, data[0] & 0x1f, regnum, data[2]); } return 0; default: @@ -967,38 +998,56 @@ tp->csr6 &= ~0x00D5; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - tp->csr6 |= 0x00C0; - csr6 |= 0x00C0; + tp->csr6 |= AcceptAllMulticast | AcceptAllPhys; + csr6 |= AcceptAllMulticast | AcceptAllPhys; /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well -- accept all multicasts. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; + tp->csr6 |= AcceptAllMulticast; + csr6 |= AcceptAllMulticast; } else if (tp->flags & MC_HASH_ONLY) { /* Some work-alikes have only a 64-entry hash filter table. */ /* Should verify correctness on big-endian/__powerpc__ */ struct dev_mc_list *mclist; int i; - u32 mc_filter[2]; /* Multicast hash filter */ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; + tp->csr6 |= AcceptAllMulticast; + csr6 |= AcceptAllMulticast; } else { - mc_filter[1] = mc_filter[0] = 0; + u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */ + int filterbit; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); - - if (tp->chip_id == AX88140) { + i++, mclist = mclist->next) { + if (tp->flags & COMET_MAC_ADDR) + filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr); + else + filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + filterbit &= 0x3f; + set_bit(filterbit, mc_filter); + if (tulip_debug > 2) { + printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:" + "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name, + mclist->dmi_addr[0], mclist->dmi_addr[1], + mclist->dmi_addr[2], mclist->dmi_addr[3], + mclist->dmi_addr[4], mclist->dmi_addr[5], + ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); + } + } + if (mc_filter[0] == tp->mc_filter[0] && + mc_filter[1] == tp->mc_filter[1]) + ; /* No change. */ + else if (tp->flags & IS_ASIX) { outl(2, ioaddr + CSR13); outl(mc_filter[0], ioaddr + CSR14); outl(3, ioaddr + CSR13); outl(mc_filter[1], ioaddr + CSR14); - } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + } else if (tp->flags & COMET_MAC_ADDR) { outl(mc_filter[0], ioaddr + 0xAC); outl(mc_filter[1], ioaddr + 0xB0); } + tp->mc_filter[0] = mc_filter[0]; + tp->mc_filter[1] = mc_filter[1]; } } else { unsigned long flags; @@ -1204,22 +1253,12 @@ tp->revision = chip_rev; tp->csr0 = csr0; spin_lock_init(&tp->lock); + spin_lock_init(&tp->mii_lock); dev->base_addr = ioaddr; dev->irq = irq; pci_set_drvdata(pdev, dev); -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); @@ -1332,15 +1371,18 @@ /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { - tp->default_port = options[board_idx] & 15; - if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + if (options[board_idx] & MEDIA_MASK) + tp->default_port = options[board_idx] & MEDIA_MASK; + if ((options[board_idx] & FullDuplex) || full_duplex[board_idx] > 0) tp->full_duplex = 1; if (mtu[board_idx] > 0) dev->mtu = mtu[board_idx]; } - if (dev->mem_start) - tp->default_port = dev->mem_start; + if (dev->mem_start & MEDIA_MASK) + tp->default_port = dev->mem_start & MEDIA_MASK; if (tp->default_port) { + printk(KERN_INFO "%s: Transceiver selection forced to %s.\n", + dev->name, medianame[tp->default_port & MEDIA_MASK]); tp->medialock = 1; if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) tp->full_duplex = 1; @@ -1365,7 +1407,7 @@ if ((tp->flags & ALWAYS_CHECK_MII) || (tp->mtable && tp->mtable->has_mii) || ( ! tp->mtable && (tp->flags & HAS_MII))) { - int phy, phy_idx; + int phyn, phy_idx = 0; if (tp->mtable && tp->mtable->has_mii) { for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == 11) { @@ -1379,8 +1421,8 @@ /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time. */ - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { + for (phyn = 1; phyn <= 32 && phy_idx < sizeof(tp->phys); phyn++) { + int phy = phyn & 0x1f; int mii_status = tulip_mdio_read(dev, phy, 1); if ((mii_status & 0x8301) == 0x8001 || ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.4.3/linux/drivers/net/wan/Config.in Tue Mar 6 19:44:37 2001 +++ linux/drivers/net/wan/Config.in Thu Apr 12 12:11:39 2001 @@ -75,15 +75,13 @@ if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool ' WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then - dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS + dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' WANPIPE Frame Relay support (OBSOLETE)' CONFIG_WANPIPE_FR - bool ' WANPIPE X.25 support (OBSOLETE)' CONFIG_WANPIPE_X25 - fi + bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE Multi-Port PPP support' CONFIG_WANPIPE_MULTPPP fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile --- v2.4.3/linux/drivers/net/wan/Makefile Tue Mar 6 19:44:37 2001 +++ linux/drivers/net/wan/Makefile Thu Apr 12 12:11:39 2001 @@ -12,11 +12,12 @@ export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o list-multi = wanpipe.o cyclomx.o -wanpipe-objs = sdlamain.o $(wanpipe-y) +wanpipe-objs = sdlamain.o sdla_ft1.o $(wanpipe-y) wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o +wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o cyclomx-objs = cycx_main.o $(cyclomx-y) cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o @@ -45,7 +46,11 @@ obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o -obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +ifeq ($(CONFIG_WANPIPE_MULTPPP),y) + obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o +else + obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +endif obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c --- v2.4.3/linux/drivers/net/wan/sdla_chdlc.c Tue Mar 6 19:44:36 2001 +++ linux/drivers/net/wan/sdla_chdlc.c Thu Apr 12 12:11:39 2001 @@ -4,14 +4,40 @@ * Authors: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * 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. * ============================================================================ -* Feb 28, 2000 Jeff Garzik softnet updates +* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the +* HDLC streaming protocol +* Added a TTY Async serial driver over the +* Async protocol. +* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support +* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. +* Tcpdump doesn't support CHDLC inteface +* types, to fix this "true type" option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the +* latest update. +* May 09, 2000 Nenad Corbic Option to bring down an interface +* upon disconnect. +* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. +* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. +* Feb 10, 2000 Gideon Hack Added ASYNC support. +* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and +* if_stats() functions. +* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, +* condition between if_open and isr. +* Jan 10, 2000 Nenad Corbic Added new socket API support. +* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels * Nov 20, 1999 Nenad Corbic Fixed zero length API bug. * Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. * Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing @@ -22,18 +48,26 @@ * Aug 07, 1998 David Fong Initial version. *****************************************************************************/ -#include <linux/config.h> #include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <linux/inetdevice.h> -#include <asm/uaccess.h> + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> + #include <linux/inetdevice.h> + #include <linux/netdevice.h> +#else + #include <asm/segment.h> + #include <net/route.h> /* Adding new route entries : 2.0.X kernels */ +#endif + #include <linux/in.h> /* sockaddr_in */ #include <linux/inet.h> #include <linux/if.h> @@ -42,32 +76,42 @@ #include <asm/io.h> #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ +#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ -/****** Defines & Macros ****************************************************/ +#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ +#include <linux/if_wanpipe.h> + +/* TTY Includes */ +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif + +/****** Defines & Macros ****************************************************/ /* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x0001 -#define TMR_INT_ENABLED_UPDATE 0x0002 - +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 + +#define MAX_IP_ERRORS 10 + +#define TTY_CHDLC_MAX_MTU 2000 #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ #define CHDLC_HDR_LEN 1 -#define IFF_POINTTOPOINT 0x10 - -#define WANPIPE 0x00 -#define API 0x01 #define CHDLC_API 0x01 #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +//#define PRINT_DEBUG +#ifdef PRINT_DEBUG +#define dbg_printk(format, a...) printk(format, ## a) +#else +#define dbg_printk(format, a...) +#endif -#define TX_TIMEOUT (5*HZ) - /******Data Structures*****************************************************/ /* This structure is placed in the private data area of the device structure. @@ -77,9 +121,7 @@ typedef struct chdlc_private_area { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + wanpipe_common_t common; sdla_t *card; int TracingEnabled; /* For enabling Tracing */ unsigned long curr_trace_addr; /* Used for Tracing */ @@ -96,12 +138,38 @@ unsigned long router_up_time; u32 IP_address; /* IP addressing */ u32 IP_netmask; + u32 ip_local; + u32 ip_remote; + u32 ip_local_tmp; + u32 ip_remote_tmp; + u8 ip_error; + u8 config_chdlc; + u8 config_chdlc_timeout; unsigned char mc; /* Mulitcast support on/off */ unsigned short udp_pkt_lgth; /* udp packet processing */ char udp_pkt_src; char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; unsigned short timer_int_enabled; char update_comms_stats; /* updating comms stats */ + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; + #endif + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; //FIXME: add driver stats as per frame relay! } chdlc_private_area_t; @@ -125,41 +193,47 @@ /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ static int update (wan_device_t* wandev); -static int new_if (wan_device_t* wandev, struct net_device* dev, +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); -static int del_if (wan_device_t* wandev, struct net_device* dev); /* Network device interface */ -static int if_init (struct net_device* dev); -static int if_open (struct net_device* dev); -static int if_close (struct net_device* dev); -static void if_tx_timeout (struct net_device *dev); -static int if_header (struct sk_buff* skb, struct net_device* dev, +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len); -#ifdef LINUX_2_1 -static int if_rebuild_hdr (struct sk_buff *skb); + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + static int if_rebuild_hdr (struct sk_buff *skb); + static struct net_device_stats* if_stats (netdevice_t* dev); + #else -static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, + static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, struct sk_buff* skb); + static struct enet_statistics* if_stats (netdevice_t* dev); #endif -static int if_send (struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats* if_stats (struct net_device* dev); + +static int if_send (struct sk_buff* skb, netdevice_t* dev); /* CHDLC Firmware interface functions */ static int chdlc_configure (sdla_t* card, void* data); static int chdlc_comm_enable (sdla_t* card); -static int chdlc_comm_disable (sdla_t* card); static int chdlc_read_version (sdla_t* card, char* str); static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); static int chdlc_send (sdla_t* card, void* data, unsigned len); static int chdlc_read_comm_err_stats (sdla_t* card); static int chdlc_read_op_stats (sdla_t* card); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); +static int chdlc_disable_comm_shutdown (sdla_t *card); +#ifdef LINUX_2_4 + static void if_tx_timeout (netdevice_t *dev); +#endif + /* Miscellaneous CHDLC Functions */ static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev ); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); +static void init_chdlc_tx_rx_buff( sdla_t* card); static int process_chdlc_exception(sdla_t *card); static int process_global_exception(sdla_t *card); static int update_comms_stats(sdla_t* card, @@ -168,23 +242,40 @@ static int unconfigure_ip (sdla_t* card); static void process_route(sdla_t *card); static void port_set_state (sdla_t *card, int); +static int config_chdlc (sdla_t *card); +static void disable_comm (sdla_t *card); + +static void trigger_chdlc_poll (netdevice_t *); +static void chdlc_poll (netdevice_t *); +static void chdlc_poll_delay (unsigned long dev_ptr); +/* Miscellaneous asynchronous interface Functions */ +static int set_asy_config (sdla_t* card); +static int asy_comm_enable (sdla_t* card); + /* Interrupt handlers */ static void wpc_isr (sdla_t* card); static void rx_intr (sdla_t* card); static void timer_intr(sdla_t *); +#if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Bottom half handlers */ + static void chdlc_bh (netdevice_t *); + static int chdlc_bh_cleanup (netdevice_t *); + static int bh_enqueue (netdevice_t *, struct sk_buff *); +#endif + /* Miscellaneous functions */ -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, struct sk_buff *skb); static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card, struct net_device *dev ); +static int intr_test( sdla_t* card); static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area); static unsigned short calc_checksum (char *, int); static void s508_lock (sdla_t *card, unsigned long *smp_flags); @@ -192,6 +283,46 @@ static int Intr_test_counter; + +/* TTY Global Definitions */ + +#if defined(LINUX_2_4) || defined(LINUX_2_1) + +#define NR_PORTS 4 +#define WAN_TTY_MAJOR 226 +#define WAN_TTY_MINOR 0 + +#define WAN_CARD(port) (tty_card_map[port]) +#define MIN_PORT 0 +#define MAX_PORT NR_PORTS-1 + +#define CRC_LENGTH 2 + +static int wanpipe_tty_init(sdla_t *card); +static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); +static void wanpipe_tty_trigger_poll(sdla_t *card); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount=1; +static int tty_init_cnt=0; + +static struct serial_state rs_table[NR_PORTS]; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +static char tty_driver_mode=WANOPT_TTY_SYNC; + +static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", + "CRTSCTS XONXOFF-RX","XONXOFF-TX", + "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; +static char *p_decode[] = {"NONE","ODD","EVEN"}; + +static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; + +#endif + + /****** Public Functions ****************************************************/ /*============================================================================ @@ -211,6 +342,7 @@ unsigned char port_num; int err; unsigned long max_permitted_baud = 0; + SHARED_MEMORY_INFO_STRUCT *flags; union { @@ -234,7 +366,7 @@ if (conf->comm_port != card->next->u.c.comm_port){ card->u.c.comm_port = conf->comm_port; }else{ - printk(KERN_ERR "%s: ERROR - %s port used!\n", + printk(KERN_INFO "%s: ERROR - %s port used!\n", card->wandev.name, PORT(conf->comm_port)); return -EINVAL; } @@ -242,7 +374,7 @@ card->u.c.comm_port = conf->comm_port; } }else{ - printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", card->wandev.name); return -EINVAL; } @@ -305,15 +437,11 @@ card->exec = NULL; card->wandev.update = &update; card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DUALPORT; + card->wandev.del_if = NULL; card->wandev.udp_port = conf->udp_port; - + card->disable_comm = &disable_comm; card->wandev.new_if_cnt = 0; - /* This is for the ports link state */ - card->u.c.state = WAN_DISCONNECTED; - /* reset the number of times the 'update()' proc has been called */ card->u.c.update_call_count = 0; @@ -331,18 +459,27 @@ port_num = card->u.c.comm_port; + /* in API mode, we can configure for "receive only" buffering */ + if(card->hw.type == SDLA_S514) { + card->u.c.receive_only = conf->receive_only; + if(conf->receive_only) { + printk(KERN_INFO + "%s: Configured for 'receive only' mode\n", + card->devname); + } + } + /* Setup Port Bps */ if(card->wandev.clocking) { - - if(port_num == WANOPT_PRI) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { /* For Primary Port 0 */ max_permitted_baud = (card->hw.type == SDLA_S514) ? PRI_MAX_BAUD_RATE_S514 : PRI_MAX_BAUD_RATE_S508; - } - else if(port_num == WANOPT_SEC) { + + }else if(port_num == WANOPT_SEC) { /* For Secondary Port 1 */ max_permitted_baud = (card->hw.type == SDLA_S514) ? @@ -357,14 +494,14 @@ printk(KERN_INFO "%s: Baud rate set to %lu bps\n", card->wandev.name, max_permitted_baud); } - card->wandev.bps = conf->bps; }else{ card->wandev.bps = 0; } /* Setup the Port MTU */ - if(port_num == WANOPT_PRI) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ card->wandev.mtu = (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? @@ -387,8 +524,6 @@ mb1->command = READ_CHDLC_CONFIGURATION; err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; if(err != COMMAND_OK) { - clear_bit(1, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514) enable_irq(card->hw.irq); @@ -406,6 +541,72 @@ ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); } + flags = card->u.c.flags; + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + + if (!card->wandev.piggyback){ + int err; + + /* Perform interrupt testing */ + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, Intr_test_counter); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, Intr_test_counter); + card->configured = 1; + } + + if ((card->tty_opt=conf->tty) == WANOPT_YES){ + #if defined(LINUX_2_4) || defined(LINUX_2_1) + int err; + card->tty_minor = conf->tty_minor; + + /* On ASYNC connections internal clocking + * is mandatory */ + if ((card->u.c.async_mode = conf->tty_mode)){ + card->wandev.clocking = 1; + } + err=wanpipe_tty_init(card); + if (err){ + return err; + } + #else + printk(KERN_INFO "%s: Error: TTY driver is not supported on 2.0.X kernels!\n", + card->devname); + return -EINVAL; + #endif + }else{ + + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: + Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + } + + /* If we are using CHDLC in backup mode, this flag will + * indicate not to look for IP addresses in config_chdlc()*/ + card->u.c.backup = conf->backup; + + printk(KERN_INFO "\n"); + return 0; } @@ -427,8 +628,8 @@ static int update (wan_device_t* wandev) { sdla_t* card = wandev->private; - struct net_device* dev = card->wandev.dev; - volatile chdlc_private_area_t* chdlc_priv_area = dev->priv; + netdevice_t* dev; + volatile chdlc_private_area_t* chdlc_priv_area; SHARED_MEMORY_INFO_STRUCT *flags; unsigned long timeout; @@ -442,10 +643,14 @@ /* more sanity checks */ if(!card->u.c.flags) return -ENODEV; - if(test_bit(1, (void*)&card->wandev.critical)) + + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) return -EAGAIN; - if(!netif_running(dev)) + if((dev=card->wandev.dev) == NULL) + return -ENODEV; + + if((chdlc_priv_area=dev->priv) == NULL) return -ENODEV; flags = card->u.c.flags; @@ -488,13 +693,17 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; chdlc_private_area_t* chdlc_priv_area; + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", + printk(KERN_INFO "%s: Invalid interface name!\n", card->devname); return -EINVAL; } @@ -506,9 +715,11 @@ return -ENOMEM; memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - + chdlc_priv_area->card = card; - + chdlc_priv_area->common.sk = NULL; + chdlc_priv_area->common.func = NULL; + /* initialize data */ strcpy(card->u.c.if_name, conf->name); @@ -523,110 +734,216 @@ chdlc_priv_area->route_status = NO_ROUTE; chdlc_priv_area->route_removed = 0; - /* Setup protocol options */ + card->u.c.async_mode = conf->async_mode; + + /* setup for asynchronous mode */ + if(conf->async_mode) { + printk(KERN_INFO "%s: Configuring for asynchronous mode\n", + wandev->name); - card->u.c.protocol_options = 0; + if(card->u.c.comm_port == WANOPT_PRI) { + printk(KERN_INFO + "%s:Asynchronous mode on secondary port only\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + } - if (conf->ignore_dcd == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; - } + if(strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO + "%s: Running in WANIPE Async Mode\n", wandev->name); + card->u.c.usedby = WANPIPE; + }else{ + card->u.c.usedby = API; + } - if (conf->ignore_cts == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; - } + if(!card->wandev.clocking) { + printk(KERN_INFO + "%s: Asynch. clocking must be 'Internal'\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + } - if (conf->ignore_keepalive == WANOPT_YES) { - card->u.c.protocol_options |= IGNORE_KPALV_FOR_LINK_STAT; - card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; - card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; - card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; + if((card->wandev.bps < MIN_ASY_BAUD_RATE) || + (card->wandev.bps > MAX_ASY_BAUD_RATE)) { + printk(KERN_INFO "%s: Selected baud rate is invalid.\n", + wandev->name); + printk(KERN_INFO "Must be between %u and %u bps.\n", + MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); + kfree(chdlc_priv_area); + return -EINVAL; + } - } else { /* Do not ignore keepalives */ + card->u.c.api_options = 0; + if (conf->asy_data_trans == WANOPT_YES) { + card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; + } + + card->u.c.protocol_options = 0; + if (conf->rts_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; + } + if (conf->dcd_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; + } + if (conf->cts_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; + } - card->u.c.kpalv_tx = - (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? - min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : - DEFAULT_Tx_KPALV_TIMER; + card->u.c.tx_bits_per_char = conf->tx_bits_per_char; + card->u.c.rx_bits_per_char = conf->rx_bits_per_char; + card->u.c.stop_bits = conf->stop_bits; + card->u.c.parity = conf->parity; + card->u.c.break_timer = conf->break_timer; + card->u.c.inter_char_timer = conf->inter_char_timer; + card->u.c.rx_complete_length = conf->rx_complete_length; + card->u.c.xon_char = conf->xon_char; + + } else { /* setup for synchronous mode */ + + card->u.c.protocol_options = 0; + if (conf->ignore_dcd == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; + } + if (conf->ignore_cts == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; + } - card->u.c.kpalv_rx = - (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? - min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : - DEFAULT_Rx_KPALV_TIMER; + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options |= + IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + card->u.c.kpalv_tx = + ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) + >= 0) ? + min(conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx = + ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) + >= 0) ? + min(conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err = + ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) + >= 0) ? + min(conf->keepalive_err_margin, + MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } - card->u.c.kpalv_err = - (conf->keepalive_err_margin - MIN_KPALV_ERR_TOL) >= 0 ? - min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : - DEFAULT_KPALV_ERR_TOL; - } + /* Setup slarp timer to control delay between slarps */ + card->u.c.slarp_timer = + ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? + min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + + #ifdef LINUX_2_0 + if (card->u.c.slarp_timer){ + printk(KERN_INFO + "%s: Error: Dynamic IP support not available for 2.0.X kernels\n", + card->devname); + printk(KERN_INFO "%s: Defaulting to Static IP addressing\n", + card->devname); + } + card->u.c.slarp_timer=0; + #endif - /* Setup slarp timer to control delay between slarps - */ - card->u.c.slarp_timer = - (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? - min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : - DEFAULT_SLARP_REQ_TIMER; + if (conf->hdlc_streaming == WANOPT_YES) { + printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", + wandev->name); + card->u.c.protocol_options = HDLC_STREAMING_MODE; + } + if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ + printk(KERN_INFO + "%s: Enabling, true interface type encoding.\n", + card->devname); + } + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { - /* If HDLC_STRAMING is enabled then IGNORE DCD, CTS and KEEPALIVES - * are automatically ignored - */ - if (conf->hdlc_streaming == WANOPT_YES) { - printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", - wandev->name); - card->u.c.protocol_options = HDLC_STREAMING_MODE; + printk(KERN_INFO "%s: Running in WANPIPE mode!\n", + wandev->name); + card->u.c.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); + printk(KERN_INFO + "%s: Dynamic interface configuration enabled\n", + card->devname); + } + + } else if( strcmp(conf->usedby, "API") == 0) { + #if defined(LINUX_2_1) || defined(LINUX_2_4) + card->u.c.usedby = API; + printk(KERN_INFO "%s: Running in API mode !\n", + wandev->name); + #else + printk(KERN_INFO "%s: API Mode is not supported for kernels lower than 2.2.X!\n", + wandev->name); + printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel fro the API support\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + #endif + } } - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO "%s: Running in WANPIPE mode !\n",wandev->name); - card->u.c.usedby = WANPIPE; - - } else if( strcmp(conf->usedby, "API") == 0){ - -#ifdef CHDLC_API - card->u.c.usedby = API; - printk(KERN_INFO "%s: Running in API mode !\n",wandev->name); -#else - printk(KERN_INFO "%s: API Mode is not supported!\n", - wandev->name); - printk(KERN_INFO "%s: Chdlc API patch can be obtained from Sangoma Tech.\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; -#endif + #if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Tells us that if this interface is a + * gateway or not */ + if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,card->u.c.if_name); } - + #endif /* Get Multicast Information */ chdlc_priv_area->mc = conf->mc; /* prepare network device data space for registration */ - strcpy(dev->name, card->u.c.if_name); + #ifdef LINUX_2_4 + strcpy(dev->name,card->u.c.if_name); + #else + dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", card->u.c.if_name); + #endif + dev->init = &if_init; dev->priv = chdlc_priv_area; - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if (wan_device_t* wandev, struct net_device* dev) -{ - -/* FIXME: This code generates kernel panic during - router stop!. Investigate futher. - (Error is dereferencing a NULL pointer) - - if(dev->priv){ - - kfree(dev->priv); - dev->priv = NULL; + /* Initialize the polling task routine */ + #ifndef LINUX_2_4 + chdlc_priv_area->poll_task.next = NULL; + #endif + chdlc_priv_area->poll_task.sync=0; + chdlc_priv_area->poll_task.routine = (void*)(void*)chdlc_poll; + chdlc_priv_area->poll_task.data = dev; + + /* Initialize the polling delay timer */ + init_timer(&chdlc_priv_area->poll_delay_timer); + chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; + chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; + + printk(KERN_INFO "\n"); - } -*/ return 0; } @@ -640,14 +957,14 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init (struct net_device* dev) +static int if_init (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; wan_device_t* wandev = &card->wandev; -#ifndef LINUX_2_1 + #ifdef LINUX_2_0 int i; -#endif + #endif /* Initialize device driver entry points */ dev->open = &if_open; @@ -656,22 +973,41 @@ dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; + #ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + #endif + /* Initialize media-specific parameters */ - dev->flags |= IFF_POINTTOPOINT; + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; /* Enable Mulitcasting if user selected */ if (chdlc_priv_area->mc == WANOPT_YES){ dev->flags |= IFF_MULTICAST; } - -#ifndef LINUX_2_1 + + #ifdef LINUX_2_0 dev->family = AF_INET; -#endif - dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ + #endif + + if (chdlc_priv_area->true_if_encoding){ + #if defined(LINUX_2_1) || defined(LINUX_2_4) + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + #else + dev->type = ARPHRD_PPP; + #endif + }else{ + dev->type = ARPHRD_PPP; + } + dev->mtu = card->wandev.mtu; + /* for API usage, add the API header size to the requested MTU size */ + if(card->u.c.usedby == API) { + dev->mtu += sizeof(api_tx_hdr_t); + } + dev->hard_header_len = CHDLC_HDR_LEN; /* Initialize hardware parameters */ @@ -688,12 +1024,12 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ -#ifdef LINUX_2_1 + #if defined(LINUX_2_1) || defined(LINUX_2_4) dev_init_buffers(dev); -#else + #else for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]); -#endif + #endif return 0; } @@ -705,85 +1041,63 @@ * * Return 0 if O.k. or errno. */ -static int if_open (struct net_device* dev) +static int if_open (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags; struct timeval tv; int err = 0; /* Only one open per interface is allowed */ - if(netif_running(dev)) + if (is_dev_running(dev)) return -EBUSY; - - if(test_and_set_bit(1, (void*)&card->wandev.critical)) { - return -EAGAIN; - } - - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - if (!card->configured && !card->wandev.piggyback){ - /* Perform interrupt testing */ - err = intr_test(card, dev); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "%s: Please choose another interrupt\n", - card->devname); - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - card->configured = 1; - }else{ - printk(KERN_INFO "%s: Card configured, skip interrupt test\n", - card->devname); - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card, dev); - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - /* Enable communications */ - if (chdlc_comm_enable(card)) { - clear_bit(1, (void*)&card->wandev.critical); - return -EIO; - } - - clear_bit(1, (void*)&card->wandev.critical); - port_set_state(card, WAN_CONNECTING); + #if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Initialize the task queue */ + chdlc_priv_area->tq_working=0; + + #ifndef LINUX_2_4 + chdlc_priv_area->common.wanpipe_task.next = NULL; + #endif + chdlc_priv_area->common.wanpipe_task.sync = 0; + chdlc_priv_area->common.wanpipe_task.routine = (void *)(void *)chdlc_bh; + chdlc_priv_area->common.wanpipe_task.data = dev; + + /* Allocate and initialize BH circular buffer */ + /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ + chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); + memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); + atomic_set(&chdlc_priv_area->bh_buff_used, 0); + #endif + do_gettimeofday(&tv); chdlc_priv_area->router_start_time = tv.tv_sec; - + + #ifdef LINUX_2_4 netif_start_queue(dev); - dev->flags |= IFF_POINTTOPOINT; + #else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + #endif + wanpipe_open(card); + /* TTY is configured during wanpipe_set_termios + * call, not here */ + if (card->tty_opt) + return err; + + set_bit(0,&chdlc_priv_area->config_chdlc); + chdlc_priv_area->config_chdlc_timeout=jiffies; + del_timer(&chdlc_priv_area->poll_delay_timer); + + /* Start the CHDLC configuration after 1sec delay. + * This will give the interface initilization time + * to finish its configuration */ + chdlc_priv_area->poll_delay_timer.expires=jiffies+HZ; + add_timer(&chdlc_priv_area->poll_delay_timer); return err; } @@ -792,25 +1106,76 @@ * o if this is the last close, then disable communications and interrupts. * o reset flags. */ -static int if_close (struct net_device* dev) +static int if_close (netdevice_t* dev) { chdlc_private_area_t* chdlc_priv_area = dev->priv; sdla_t* card = chdlc_priv_area->card; - if(test_and_set_bit(1, (void*)&card->wandev.critical)) - return -EAGAIN; + #if defined(LINUX_2_1) || defined(LINUX_2_4) - netif_stop_queue(dev); + if (chdlc_priv_area->bh_head){ + int i; + struct sk_buff *skb; + + for (i=0; i<(MAX_BH_BUFF+1); i++){ + skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; + if (skb != NULL){ + wan_dev_kfree_skb(skb, FREE_READ); + } + } + kfree(chdlc_priv_area->bh_head); + chdlc_priv_area->bh_head=NULL; + } + #endif + + stop_net_queue(dev); + #ifndef LINUX_2_4 + dev->start=0; + #endif wanpipe_close(card); - port_set_state(card, WAN_DISCONNECTED); - chdlc_set_intr_mode(card, 0); - chdlc_comm_disable(card); + del_timer(&chdlc_priv_area->poll_delay_timer); + return 0; +} + +static void disable_comm (sdla_t *card) +{ + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + if (card->u.c.comm_enabled){ + chdlc_disable_comm_shutdown (card); + }else{ + flags->interrupt_info_struct.interrupt_permission = 0; + } - clear_bit(1, (void*)&card->wandev.critical); + #if defined(LINUX_2_4) || defined(LINUX_2_1) + if (!tty_init_cnt) + return; - return 0; + if (card->tty_opt){ + struct serial_state * state; + if (!(--tty_init_cnt)){ + int e1,e2; + *serial_driver.refcount=0; + + if ((e1 = tty_unregister_driver(&serial_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", + card->devname,WAN_TTY_MAJOR); + } + card->tty=NULL; + tty_card_map[card->tty_minor]=NULL; + state = &rs_table[card->tty_minor]; + memset(state,0,sizeof(state)); + } + #endif + return; } + /*============================================================================ * Build media header. * @@ -820,7 +1185,7 @@ * * Return: media header length. */ -static int if_header (struct sk_buff* skb, struct net_device* dev, +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len) { skb->protocol = htons(type); @@ -828,48 +1193,49 @@ return CHDLC_HDR_LEN; } + +#ifdef LINUX_2_4 /*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved + * Handle transmit timeout event from netif watchdog */ -#ifdef LINUX_2_1 -static int if_rebuild_hdr (struct sk_buff *skb) +static void if_tx_timeout (netdevice_t *dev) { - return 1; -} -#else -static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, - struct sk_buff* skb) -{ - return 1; + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); } #endif + /*============================================================================ - * Handle transmit timeout event from netif watchdog + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved */ -static void if_tx_timeout (struct net_device *dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static int if_rebuild_hdr (struct sk_buff *skb) { - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timeout !\n", - card->devname); - - /* unbusy the interface */ - netif_wake_queue (dev); + return 1; } - +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb) +{ + return 1; +} +#endif /*============================================================================ * Send a packet on a network interface. @@ -888,7 +1254,7 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff* skb, struct net_device* dev) +static int if_send (struct sk_buff* skb, netdevice_t* dev) { chdlc_private_area_t *chdlc_priv_area = dev->priv; sdla_t *card = chdlc_priv_area->card; @@ -896,33 +1262,68 @@ INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; int udp_type = 0; unsigned long smp_flags; + int err=0; - if(skb == NULL) { + #ifdef LINUX_2_4 + netif_stop_queue(dev); + #endif + + if (skb == NULL){ /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", card->devname, dev->name); - netif_wake_queue(dev); + + wake_net_dev(dev); return 0; } - if(ntohs(skb->protocol) != 0x16) { + #ifndef LINUX_2_4 + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit timeout !\n", + card->devname); + + /* unbusy the interface */ + clear_bit(0,&dev->tbusy); + } + #endif + + if (ntohs(skb->protocol) != htons(PVC_PROT)){ /* check the udp packet type */ + udp_type = udp_pkt_type(skb, card); - if(udp_type == UDP_CPIPE_TYPE) { + + if (udp_type == UDP_CPIPE_TYPE){ if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)) + chdlc_priv_area)){ chdlc_int->interrupt_permission |= APP_INT_ON_TIMER; + } + start_net_queue(dev); return 0; } /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)) - return 0; + if(chk_bcast_mcast_addr(card, dev, skb)){ + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; + } } /* Lock the 508 Card: SMP is supported */ @@ -930,29 +1331,24 @@ s508_lock(card,&smp_flags); } - if(test_and_set_bit(0, (void*)&card->wandev.critical)) { + if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped; -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - return 0; + start_net_queue(dev); + goto if_send_exit_crit; } - if(card->u.c.state != WAN_CONNECTED) + if(card->u.c.state != WAN_CONNECTED){ ++card->wandev.stats.tx_dropped; - - else if(!skb->protocol) + start_net_queue(dev); + + }else if(!skb->protocol){ ++card->wandev.stats.tx_errors; - - else { + start_net_queue(dev); + + }else { void* data = skb->data; unsigned len = skb->len; unsigned char attr; @@ -964,18 +1360,14 @@ if (card->u.c.usedby == API){ api_tx_hdr_t* api_tx_hdr; - if (len <= sizeof(api_tx_hdr_t)){ -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif + /* discard the frame if we are configured for */ + /* 'receive only' mode or if there is no data */ + if (card->u.c.receive_only || + (len <= sizeof(api_tx_hdr_t))) { + ++card->wandev.stats.tx_dropped; - clear_bit(0, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - return 0; + start_net_queue(dev); + goto if_send_exit_crit; } api_tx_hdr = (api_tx_hdr_t *)data; @@ -985,24 +1377,36 @@ } if(chdlc_send(card, data, len)) { - netif_stop_queue(dev); - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - else { + stop_net_queue(dev); + }else{ ++card->wandev.stats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.tx_bytes += len; + #endif + + start_net_queue(dev); + + #ifdef LINUX_2_4 + dev->trans_start = jiffies; + #endif } } - if (!netif_queue_stopped(dev)) - dev_kfree_skb(skb); +if_send_exit_crit: + + if (!(err=is_queue_stopped(dev))) { + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + chdlc_priv_area->tick_counter = jiffies; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; + } - clear_bit(0, (void*)&card->wandev.critical); + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } - return netif_queue_stopped(dev); + + return err; } @@ -1011,19 +1415,19 @@ * multicast source IP address. */ -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb) { u32 src_ip_addr; u32 broadcast_ip_addr = 0; -#ifdef LINUX_2_1 + #if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; -#endif + #endif /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 12); /* read the IP broadcast address for the device */ -#ifdef LINUX_2_1 + #if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; @@ -1032,20 +1436,14 @@ else return 0; } -#else + #else broadcast_ip_addr = dev->pa_brdaddr; -#endif + #endif /* check if the IP Source Address is a Broadcast address */ if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - ++card->wandev.stats.tx_dropped; return 1; } @@ -1054,12 +1452,6 @@ (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - ++card->wandev.stats.tx_dropped; return 1; } @@ -1169,23 +1561,29 @@ /*============================================================================ * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Return a pointer to struct enet_statistics. */ -#ifdef LINUX_2_1 -static struct net_device_stats* if_stats (struct net_device* dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats* if_stats (netdevice_t* dev) { sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area = dev->priv; + chdlc_private_area_t* chdlc_priv_area; + + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; my_card = chdlc_priv_area->card; return &my_card->wandev.stats; } #else -static struct net_device_stats* if_stats (struct net_device* dev) +static struct enet_statistics* if_stats (netdevice_t* dev) { sdla_t *my_card; chdlc_private_area_t* chdlc_priv_area = dev->priv; + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + my_card = chdlc_priv_area->card; return &my_card->wandev.stats; } @@ -1261,44 +1659,63 @@ } -/*============================================================================ - * Enable communications. - */ +/*=========================================================== + * chdlc_disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call chdlc_error() hander since the private + * area has already been replaced */ -static int chdlc_comm_enable (sdla_t* card) +static int chdlc_disable_comm_shutdown (sdla_t *card) { - int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + /* Disable Interrutps */ + int_data->CHDLC_interrupt_triggers = 0; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 1; + + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + /* Disable Communications */ + + if (card->u.c.async_mode) { + mb->command = DISABLE_ASY_COMMUNICATIONS; + }else{ + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + } + mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - return err; + + card->u.c.comm_enabled = 0; + + return 0; } /*============================================================================ - * Disable communications and Drop the Modem lines (DCD and RTS). + * Enable communications. */ -static int chdlc_comm_disable (sdla_t* card) + +static int chdlc_comm_enable (sdla_t* card) { int err; CHDLC_MAILBOX_STRUCT* mb = card->mbox; mb->buffer_length = 0; - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - - mb->command = SET_MODEM_STATUS; - mb->buffer_length = 1; - mb->data[0] = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if (err != COMMAND_OK) - chdlc_error(card,err,mb); - + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled = 1; + return err; } @@ -1397,10 +1814,10 @@ /* Update transmit buffer control fields */ card->u.c.txbuf = ++txbuf; - + if ((void*)txbuf > card->u.c.txbuf_last) card->u.c.txbuf = card->u.c.txbuf_base; - + return 0; } @@ -1420,7 +1837,7 @@ switch (err) { case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", + printk(KERN_INFO "%s: command 0x%02X timed out!\n", card->devname, cmd); break; @@ -1440,17 +1857,112 @@ return 0; } +#if defined(LINUX_2_1) || defined(LINUX_2_4) +/********** Bottom Half Handlers ********************************************/ + +/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. + * DO NOT INSERT ANY CODE HERE, NOTICE THE + * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE + * DOING */ + +static void chdlc_bh (netdevice_t * dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + struct sk_buff *skb; + + if (atomic_read(&chan->bh_buff_used) == 0){ + clear_bit(0, &chan->tq_working); + return; + } + + while (atomic_read(&chan->bh_buff_used)){ + + skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; + + if (skb != NULL){ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + ++card->wandev.stats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + chdlc_bh_cleanup(dev); + continue; + } + + if (chan->common.func(skb,dev,chan->common.sk) != 0){ + /* Sock full cannot send, queue us for another + * try */ + atomic_set(&chan->common.receive_block,1); + return; + }else{ + chdlc_bh_cleanup(dev); + } + }else{ + chdlc_bh_cleanup(dev); + } + } + clear_bit(0, &chan->tq_working); + + return; +} + +static int chdlc_bh_cleanup (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + + ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; + + if (chan->bh_read == MAX_BH_BUFF){ + chan->bh_read=0; + }else{ + ++chan->bh_read; + } + + atomic_dec(&chan->bh_buff_used); + return 0; +} + + + +static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb) +{ + /* Check for full */ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ + ++card->wandev.stats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + return 1; + } + + ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; + + if (chan->bh_write == MAX_BH_BUFF){ + chan->bh_write=0; + }else{ + ++chan->bh_write; + } + + atomic_inc(&chan->bh_buff_used); + + return 0; +} + +/* END OF API BH Support */ + +#endif + /****** Interrupt Handlers **************************************************/ /*============================================================================ * Cisco HDLC interrupt service routine. */ -STATIC void wpc_isr (sdla_t* card) +static void wpc_isr (sdla_t* card) { - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area; + netdevice_t* dev; SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i, interrupt_serviced = 0; + int i; sdla_t *my_card; @@ -1462,95 +1974,97 @@ flags = card->u.c.flags; if (!flags->interrupt_info_struct.interrupt_type){ /* Check for a second port (piggybacking) */ - if((my_card = card->next)){ + if ((my_card = card->next)){ flags = my_card->u.c.flags; if (flags->interrupt_info_struct.interrupt_type){ card = my_card; + card->isr(card); + return; } } } + flags = card->u.c.flags; + card->in_isr = 1; dev = card->wandev.dev; - card->in_isr = 1; + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if (!card->tty_opt && !dev && + flags->interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + + goto isr_done; + } /* if critical due to peripheral operations * ie. update() or getstats() then reset the interrupt and * wait for the board to retrigger. */ - if(test_bit(1, (void*)&card->wandev.critical)) { - if(card->u.c.flags != NULL) { - flags = card->u.c.flags; - if(flags->interrupt_info_struct. - interrupt_type) { - flags->interrupt_info_struct. - interrupt_type = 0; - } - } - card->in_isr = 0; - return; + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "ISR CRIT TO PERI\n"); + goto isr_done; } - /* On a 508 Card, if critical due to if_send - * Major Error !!! - */ + * Major Error !!! */ if(card->hw.type != SDLA_S514) { - if(test_and_set_bit(0, (void*)&card->wandev.critical)) { + if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR: %lx\n", card->devname, card->wandev.critical); card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; return; } } - /* FIXME: Take this check out later in the future */ - if(card->u.c.flags != NULL) { - - flags = card->u.c.flags; + switch(flags->interrupt_info_struct.interrupt_type) { - switch(flags->interrupt_info_struct.interrupt_type) { + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - interrupt_serviced = 1; - rx_intr(card); - break; + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TX_FRAME; - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - interrupt_serviced = 1; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; + #if defined(LINUX_2_1) || defined(LINUX_2_4) - chdlc_priv_area = dev->priv; - netif_wake_queue(dev); + if (card->tty_opt){ + wanpipe_tty_trigger_poll(card); break; + } - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - interrupt_serviced = 1; - ++ Intr_test_counter; - break; + if (dev && is_queue_stopped(dev)){ + if (card->u.c.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + #else + wake_net_dev(dev); + #endif + break; - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - interrupt_serviced = 1; - process_chdlc_exception(card); - break; + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ Intr_test_counter; + break; - case GLOBAL_EXCEP_COND_APP_INT_PEND: - interrupt_serviced = 1; - process_global_exception(card); - break; + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_chdlc_exception(card); + break; - case TIMER_APP_INT_PEND: - interrupt_serviced = 1; - timer_intr(card); - break; + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + break; - default: - break; - } - } + case TIMER_APP_INT_PEND: + timer_intr(card); + break; - if(!interrupt_serviced) { + default: printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", card->devname, flags->interrupt_info_struct.interrupt_type); @@ -1563,14 +2077,14 @@ printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); + break; } +isr_done: + card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; - if(card->hw.type != SDLA_S514){ - clear_bit(0, (void*)&card->wandev.critical); - } - + return; } /*============================================================================ @@ -1578,15 +2092,16 @@ */ static void rx_intr (sdla_t* card) { - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - void *buf; - int i,udp_type; - + netdevice_t *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; + struct sk_buff *skb; + unsigned len; + unsigned addr = rxbuf->ptr_data_bfr; + void *buf; + int i,udp_type; + if (rxbuf->opp_flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", @@ -1600,90 +2115,132 @@ printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); return; } + len = rxbuf->frame_length; + + #if defined(LINUX_2_4) || defined(LINUX_2_1) + if (card->tty_opt){ + + if (rxbuf->error_flag){ + goto rx_exit; + } + + if (len <= CRC_LENGTH){ + goto rx_exit; + } + + if (!card->u.c.async_mode){ + len -= CRC_LENGTH; + } + + wanpipe_tty_receive(card,addr,len); + goto rx_exit; + } + #endif + dev = card->wandev.dev; - chdlc_priv_area = dev->priv; - if(dev && netif_running(dev)) { + if (!dev){ + goto rx_exit; + } + + if (!is_dev_running(dev)) + goto rx_exit; - len = rxbuf->frame_length; + chdlc_priv_area = dev->priv; - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); - if (skb != NULL) { - /* Copy data to the socket buffer */ - unsigned addr = rxbuf->ptr_data_bfr; - - if((addr + len) > - card->u.c.rx_top + 1) { - unsigned tmp = - card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } + if (skb == NULL) { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top + 1) { + unsigned tmp = card->u.c.rx_top - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base; + len -= tmp; + } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); - /* Decapsulate packet */ - skb->protocol = htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); - card->wandev.stats.rx_packets ++; -#ifdef LINUX_2_1 - card->wandev.stats.rx_bytes += skb->len; + card->wandev.stats.rx_packets ++; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.rx_bytes += skb->len; #endif - udp_type = udp_pkt_type( skb, card ); + udp_type = udp_pkt_type( skb, card ); - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + flags->interrupt_info_struct. interrupt_permission |= APP_INT_ON_TIMER; - } - - } else { - - if(card->u.c.usedby == API) { - api_rx_hdr_t* api_rx_hdr; - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = - (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->error_flag = - rxbuf->error_flag; - api_rx_hdr->time_stamp = - rxbuf->time_stamp; - skb->protocol = htons(0x16); - skb->pkt_type = PACKET_HOST; - } - -/* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic - ++ chdlc_priv_area->if_stats.multicast; -*/ - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - } + } +#if defined(LINUX_2_1) || defined(LINUX_2_4) + } else if(card->u.c.usedby == API) { - } else { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; + api_rx_hdr_t* api_rx_hdr; + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->error_flag = rxbuf->error_flag; + api_rx_hdr->time_stamp = rxbuf->time_stamp; + + skb->protocol = htons(PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + bh_enqueue(dev, skb); + + if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)){ + wanpipe_queue_tq(&chdlc_priv_area->common.wanpipe_task); + wanpipe_mark_bh(); } - } +#endif + }else{ + /* FIXME: we should check to see if the received packet is a + multicast packet so that we can increment the multicast + statistic + ++ chdlc_priv_area->if_stats.multicast; + */ + /* Pass it up the protocol stack */ + + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } +rx_exit: /* Release buffer element and calculate a pointer to the next one */ rxbuf->opp_flag = 0x00; card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last) + if((void*)rxbuf > card->u.c.rxbuf_last){ card->u.c.rxmb = card->u.c.rxbuf_base; + } } /*============================================================================ @@ -1694,14 +2251,26 @@ */ void timer_intr(sdla_t *card) { - struct net_device* dev; + netdevice_t* dev; chdlc_private_area_t* chdlc_priv_area = NULL; SHARED_MEMORY_INFO_STRUCT* flags = NULL; - dev = card->wandev.dev; + if ((dev = card->wandev.dev)==NULL){ + flags = card->u.c.flags; + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + return; + } + chdlc_priv_area = dev->priv; - /* process a udp call if pending */ + if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + if (!config_chdlc(card)){ + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + } + + /* process a udp call if pending */ if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { process_udp_mgmt_pkt(card, dev, chdlc_priv_area); @@ -1733,16 +2302,14 @@ static int set_chdlc_config(sdla_t* card) { - - struct net_device * dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; CHDLC_CONFIGURATION_STRUCT cfg; memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - if(card->wandev.clocking) + if(card->wandev.clocking){ cfg.baud_rate = card->wandev.bps; - + } + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; @@ -1750,9 +2317,18 @@ cfg.modem_status_timer = 100; cfg.CHDLC_protocol_options = card->u.c.protocol_options; - cfg.percent_data_buffer_for_Tx = 50; + + if (card->tty_opt){ + cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; + } + + cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | CHDLC_RX_DATA_BYTE_COUNT_STAT); + + if (card->tty_opt){ + card->wandev.mtu = TTY_CHDLC_MAX_MTU; + } cfg.max_CHDLC_data_field_length = card->wandev.mtu; cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; cfg.receive_keepalive_timer = card->u.c.kpalv_rx; @@ -1762,9 +2338,12 @@ if (cfg.SLARP_request_timer) { cfg.IP_address = 0; cfg.IP_netmask = 0; - } - else { -#ifdef LINUX_2_1 + + }else if (card->wandev.dev){ + netdevice_t * dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev = dev->ip_ptr; if(in_dev != NULL) { @@ -1773,10 +2352,8 @@ if (ifa != NULL ) { cfg.IP_address = ntohl(ifa->ifa_local); cfg.IP_netmask = ntohl(ifa->ifa_mask); - chdlc_priv_area->IP_address = - ntohl(ifa->ifa_local); - chdlc_priv_area->IP_netmask = - ntohl(ifa->ifa_mask); + chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); + chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); } } #else @@ -1803,6 +2380,70 @@ } +/*----------------------------------------------------------------------------- + set_asy_config() used to set asynchronous configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_asy_config(sdla_t* card) +{ + + ASY_CONFIGURATION_STRUCT cfg; + CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int err; + + memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.asy_API_options = card->u.c.api_options; + cfg.asy_protocol_options = card->u.c.protocol_options; + cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; + cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; + cfg.stop_bits = card->u.c.stop_bits; + cfg.parity = card->u.c.parity; + cfg.break_timer = card->u.c.break_timer; + cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; + cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; + cfg.XON_char = card->u.c.xon_char; + cfg.XOFF_char = card->u.c.xoff_char; + cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + + mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); + memcpy(mailbox->data, &cfg, mailbox->buffer_length); + mailbox->command = SET_ASY_CONFIGURATION; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mailbox); + return err; +} + +/*============================================================================ + * Enable asynchronous communications. + */ + +static int asy_comm_enable (sdla_t* card) +{ + + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_ASY_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK && card->wandev.dev) + chdlc_error(card, err, mb); + + if (!err) + card->u.c.comm_enabled = 1; + + return err; +} /*============================================================================ * Process global exception condition @@ -1830,7 +2471,8 @@ printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); break; case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); break; + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; case ((DCD_HIGH | CTS_HIGH)): printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); break; @@ -1850,6 +2492,19 @@ card->devname); break; + case 0x17: + if (card->tty_opt){ + if (card->tty && card->tty_open){ + printk(KERN_INFO + "%s: Modem Hangup Exception: Hanging Up!\n", + card->devname); + tty_hangup(card->tty); + } + break; + } + + /* If TTY is not used just drop throught */ + default: printk(KERN_INFO "%s: Global exception %x\n", card->devname, mbox->return_code); @@ -1877,11 +2532,13 @@ case EXCEP_LINK_ACTIVE: port_set_state(card, WAN_CONNECTED); + trigger_chdlc_poll(card->wandev.dev); break; case EXCEP_LINK_INACTIVE_MODEM: port_set_state(card, WAN_DISCONNECTED); unconfigure_ip(card); + trigger_chdlc_poll(card->wandev.dev); break; case EXCEP_LINK_INACTIVE_KPALV: @@ -1889,6 +2546,7 @@ printk(KERN_INFO "%s: Keepalive timer expired.\n", card->devname); unconfigure_ip(card); + trigger_chdlc_poll(card->wandev.dev); break; case EXCEP_IP_ADDRESS_DISCOVERED: @@ -1919,10 +2577,16 @@ static int configure_ip (sdla_t* card) { - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area; char err; + if (!dev) + return 0; + + chdlc_priv_area = dev->priv; + + /* set to discover */ if(card->u.c.slarp_timer != 0x00) { CHDLC_MAILBOX_STRUCT* mb = card->mbox; @@ -1940,14 +2604,14 @@ cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; chdlc_priv_area->IP_address = cfg->IP_address; chdlc_priv_area->IP_netmask = cfg->IP_netmask; - } - /* Set flag to add route */ - chdlc_priv_area->route_status = ADD_ROUTE; + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; - /* The idea here is to add the route in the poll routine. - This way, we aren't in interrupt context when adding routes */ - card->poll = process_route; + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + trigger_chdlc_poll(dev); + } return 0; } @@ -1960,17 +2624,23 @@ static int unconfigure_ip (sdla_t* card) { - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area= dev->priv; + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area; + + if (!dev) + return 0; + chdlc_priv_area= dev->priv; + if (chdlc_priv_area->route_status == ROUTE_ADDED) { - chdlc_priv_area->route_status = REMOVE_ROUTE; - /* The idea here is to delete the route in - * the poll routine. - * This way, we aren't in interrupt context - * when adding routes + + /* Note: If this function is called, the + * port state has been DISCONNECTED. This state + * change will trigger a poll_disconnected + * function, that will check for this condition. */ - card->poll = process_route; + chdlc_priv_area->route_status = REMOVE_ROUTE; + } return 0; } @@ -1982,14 +2652,14 @@ static void process_route (sdla_t *card) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; unsigned char port_num; chdlc_private_area_t *chdlc_priv_area = NULL; u32 local_IP_addr = 0; u32 remote_IP_addr = 0; u32 IP_netmask, IP_addr; int err = 0; -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; mm_segment_t fs; struct ifreq if_info; @@ -2002,16 +2672,25 @@ chdlc_priv_area = dev->priv; port_num = card->u.c.comm_port; + /* Bug Fix Mar 16 2000 + * AND the IP address to the Mask before checking + * the last two bits. */ + if((chdlc_priv_area->route_status == ADD_ROUTE) && - ((chdlc_priv_area->IP_address & 0x000000FF) > 2)) { + ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { + printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); + if(card->u.c.slarp_timer) { + printk(KERN_INFO "%s: Bad IP address %s received\n", card->devname, in_ntoa(ntohl(chdlc_priv_area->IP_address))); printk(KERN_INFO "%s: from remote station.\n", card->devname); + }else{ + printk(KERN_INFO "%s: Bad IP address %s issued\n", card->devname, in_ntoa(ntohl(chdlc_priv_area->IP_address))); @@ -2033,11 +2712,10 @@ /* do not remove a bad route that has already been removed */ if(chdlc_priv_area->route_removed) { - card->poll = NULL; return; } -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { @@ -2058,7 +2736,17 @@ */ IP_netmask = ntohl(chdlc_priv_area->IP_netmask); remote_IP_addr = ntohl(chdlc_priv_area->IP_address); - local_IP_addr = (remote_IP_addr & ntohl(0xFFFFFF00)) + + + + /* If Netmask is 255.255.255.255 the local address + * calculation will fail. Default it back to 255.255.255.0 */ + if (IP_netmask == 0xffffffff) + IP_netmask &= 0x00ffffff; + + /* Bug Fix Mar 16 2000 + * AND the Remote IP address with IP netmask, instead + * of static netmask of 255.255.255.0 */ + local_IP_addr = (remote_IP_addr & IP_netmask) + (~remote_IP_addr & ntohl(0x0003)); if(!card->u.c.slarp_timer) { @@ -2071,7 +2759,7 @@ fs = get_fs(); /* Save file system */ set_fs(get_ds()); /* Get user space block */ -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Setup a structure for adding/removing routes */ memset(&if_info, 0, sizeof(if_info)); strcpy(if_info.ifr_name, dev->name); @@ -2099,7 +2787,7 @@ case ADD_ROUTE: if(!card->u.c.slarp_timer) { -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; if_data2->sin_addr.s_addr = remote_IP_addr; if_data2->sin_family = AF_INET; @@ -2108,7 +2796,7 @@ err = ip_rt_new(&route); #endif } else { -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; if_data1->sin_addr.s_addr = local_IP_addr; if_data1->sin_family = AF_INET; @@ -2141,7 +2829,7 @@ case REMOVE_ROUTE: -#ifdef LINUX_2_1 +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Change the local ip address of the interface to 0. * This will also delete the destination route. */ @@ -2179,9 +2867,6 @@ set_fs(fs); /* Restore file system */ - /* Once we've processed the route, stop polling */ - card->poll = NULL; - } @@ -2190,7 +2875,7 @@ */ static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area ) { int udp_pkt_stored = 0; @@ -2204,15 +2889,12 @@ udp_pkt_stored = 1; } -#ifdef LINUX_2_1 - dev_kfree_skb(skb); -#else - if(udp_pkt_src == UDP_PKT_FRM_STACK) - dev_kfree_skb(skb, FREE_WRITE); - else - dev_kfree_skb(skb, FREE_READ); -#endif - + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + return(udp_pkt_stored); } @@ -2221,7 +2903,7 @@ * Process UDP management packet. */ -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, chdlc_private_area_t* chdlc_priv_area ) { unsigned char *buf; @@ -2240,22 +2922,30 @@ chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - switch(chdlc_udp_pkt->cblock.command) { + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - case FT1_MONITOR_STATUS_CTRL: - case CPIPE_ENABLE_TRACING: - case CPIPE_DISABLE_TRACING: - case CPIPE_GET_TRACE_INFO: - case SET_FT1_MODE: - if(chdlc_priv_area->udp_pkt_src == - UDP_PKT_FRM_NETWORK) { - udp_mgmt_req_valid = 0; - } - break; - - default: - break; - } + /* Only these commands are support for remote debugging. + * All others are not */ + switch(chdlc_udp_pkt->cblock.command) { + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_CHDLC_LINK_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_CHDLC_OPERATIONAL_STATS: + + /* These two commands are executed for + * each request */ + case READ_CHDLC_CONFIGURATION: + case READ_CHDLC_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } if(!udp_mgmt_req_valid) { @@ -2265,6 +2955,12 @@ /* set return code */ chdlc_udp_pkt->cblock.return_code = 0xCD; + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,chdlc_udp_pkt->cblock.command); + } + } else { unsigned long trace_status_cfg_addr = 0; TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; @@ -2488,11 +3184,12 @@ ((unsigned char *)chdlc_udp_pkt->data )[1] = flags->FT1_info_struct.parallel_port_B_input; - + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + chdlc_udp_pkt->cblock.buffer_length = 2; mb->buffer_length = 2; break; - + case CPIPE_ROUTER_UP_TIME: do_gettimeofday( &tv ); chdlc_priv_area->router_up_time = tv.tv_sec - @@ -2500,6 +3197,8 @@ *(unsigned long *)&chdlc_udp_pkt->data = chdlc_priv_area->router_up_time; mb->buffer_length = sizeof(unsigned long); + chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; break; case FT1_MONITOR_STATUS_CTRL: @@ -2525,8 +3224,10 @@ break; } } - + goto dflt_1; + default: +dflt_1: /* it's a board command */ mb->command = chdlc_udp_pkt->cblock.command; mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; @@ -2556,12 +3257,19 @@ len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; -#ifdef LINUX_2_1 - card->wandev.stats.tx_bytes += len; -#endif + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)) { + + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.tx_bytes += len; + #endif + } } } else { @@ -2595,7 +3303,7 @@ * Initialize Receive and Transmit Buffers. */ -static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev ) +static void init_chdlc_tx_rx_buff( sdla_t* card) { CHDLC_MAILBOX_STRUCT* mb = card->mbox; CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; @@ -2607,7 +3315,9 @@ err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; if(err != COMMAND_OK) { - chdlc_error(card,err,mb); + if (card->wandev.dev){ + chdlc_error(card,err,mb); + } return; } @@ -2678,19 +3388,13 @@ * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR * _TEST_COUNTER times. */ -static int intr_test( sdla_t* card, struct net_device *dev ) +static int intr_test( sdla_t* card) { CHDLC_MAILBOX_STRUCT* mb = card->mbox; int err,i; Intr_test_counter = 0; - - /* The critical flag is unset because during intialization (if_open) - * we want the interrupts to be enabled so that when the wpc_isr is - * called it does not exit due to critical flag set. - */ - - clear_bit(1, (void*)&card->wandev.critical); + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); if (err == CMD_OK) { @@ -2707,8 +3411,6 @@ } err = chdlc_set_intr_mode(card, 0); - set_bit(1, (void*)&card->wandev.critical); - if (err != CMD_OK) return err; @@ -2723,13 +3425,33 @@ { chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; +#ifdef _WAN_UDP_DEBUG + printk(KERN_INFO "SIG %s = %s\n\ + UPP %x = %x\n\ + PRT %x = %x\n\ + REQ %i = %i\n\ + 36 th = %x 37th = %x\n", + chdlc_udp_pkt->wp_mgmt.signature, + UDPMGMT_SIGNATURE, + chdlc_udp_pkt->udp_pkt.udp_dst_port, + ntohs(card->wandev.udp_port), + chdlc_udp_pkt->ip_pkt.protocol, + UDPMGMT_UDP_PROTOCOL, + chdlc_udp_pkt->wp_mgmt.request_reply, + UDPMGMT_REQUEST, + skb->data[36], skb->data[37]); +#endif + if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + return UDP_CPIPE_TYPE; + + }else{ + return UDP_INVALID_TYPE; } - else return UDP_INVALID_TYPE; } /*============================================================================ @@ -2744,7 +3466,7 @@ case WAN_CONNECTED: printk (KERN_INFO "%s: Link connected!\n", card->devname); - break; + break; case WAN_CONNECTING: printk (KERN_INFO "%s: Link connecting...\n", @@ -2758,31 +3480,1268 @@ } card->wandev.state = card->u.c.state = state; + if (card->wandev.dev){ + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + chdlc_priv_area->common.state = state; + } } } -void s508_lock (sdla_t *card, unsigned long *smp_flags) +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card) { -#ifdef CONFIG_SMP - spin_lock_irqsave(&card->lock, *smp_flags); - if (card->next){ - spin_lock(&card->next->lock); - } -#else - disable_irq(card->hw.irq); -#endif + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + if (card->u.c.comm_enabled){ + + /* Jun 20. 2000: NC + * IP addresses are not used in the API mode */ + + if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || + chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && + card->u.c.usedby == WANPIPE) { + + /* The IP addersses have changed, we must + * stop the communications and reconfigure + * the card. Reason: the firmware must know + * the local and remote IP addresses. */ + disable_comm(card); + port_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO + "%s: IP addresses changed!\n", + card->devname); + printk(KERN_INFO + "%s: Restarting communications ...\n", + card->devname); + }else{ + /* IP addresses are the same and the link is up, + * we dont have to do anything here. Therefore, exit */ + return 0; + } + } + + chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; + chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; + + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return 0; + } + }else{ + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC configuration!\n", + card->devname); + return 0; + } + } + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return 0; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + /* In TTY mode, receive interrupt will be enabled during + * wanpipe_tty_open() operation */ + if (card->tty_opt){ + flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; + } + + /* Enable communications */ + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return 0; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return 0; + } + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + port_set_state(card, WAN_CONNECTING); + return 0; } -void s508_unlock (sdla_t *card, unsigned long *smp_flags) + +/*============================================================ + * chdlc_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * CHDLC polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each CHDLC + * interface through a tq_schedule bottom half. + * + * trigger_chdlc_poll() function is used to kick + * the chldc_poll routine. + */ + +static void chdlc_poll (netdevice_t *dev) { -#ifdef CONFIG_SMP - if (card->next){ - spin_unlock(&card->next->lock); - } - spin_unlock_irqrestore(&card->lock, *smp_flags); -#else - enable_irq(card->hw.irq); -#endif + chdlc_private_area_t *chdlc_priv_area; + sdla_t *card; + u8 check_gateway=0; + SHARED_MEMORY_INFO_STRUCT* flags; + + + if (!dev || (chdlc_priv_area=dev->priv) == NULL) + return; + + card = chdlc_priv_area->card; + flags = card->u.c.flags; + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* if_open() function has triggered the polling routine + * to determine the configured IP addresses. Once the + * addresses are found, trigger the chdlc configuration */ + if (test_bit(0,&chdlc_priv_area->config_chdlc)){ + + chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); + chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + /* Jun 20. 2000 Bug Fix + * Only perform this check in WANPIPE mode, since + * IP addresses are not used in the API mode. */ + + if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && + card->u.c.slarp_timer == 0x00 && + !card->u.c.backup && + card->u.c.usedby == WANPIPE){ + + if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ + printk(KERN_INFO "\n%s: --- WARNING ---\n", + card->devname); + printk(KERN_INFO + "%s: The local IP address is the same as the\n", + card->devname); + printk(KERN_INFO + "%s: Point-to-Point IP address.\n", + card->devname); + printk(KERN_INFO "%s: --- WARNING ---\n\n", + card->devname); + }else{ + clear_bit(POLL_CRIT,&card->wandev.critical); + chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&chdlc_priv_area->poll_delay_timer); + return; + } + } + + clear_bit(0,&chdlc_priv_area->config_chdlc); + clear_bit(POLL_CRIT,&card->wandev.critical); + + chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + return; + } + /* Dynamic interface implementation, as well as dynamic + * routing. */ + + switch (card->u.c.state){ + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the netowrk interface */ + + if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && + !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && + card->wandev.dev->flags & IFF_UP){ + + printk(KERN_INFO "%s: Interface %s down.\n", + card->devname,card->wandev.dev->name); + change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); + chdlc_priv_area->route_status = NO_ROUTE; + + }else{ + /* We need to check if the local IP address is + * zero. If it is, we shouldn't try to remove it. + */ + + if (card->wandev.dev->flags & IFF_UP && + get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && + chdlc_priv_area->route_status != NO_ROUTE && + card->u.c.slarp_timer){ + + process_route(card); + } + } + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && + test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && + !(card->wandev.dev->flags & IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s up.\n", + card->devname,card->wandev.dev->name); + change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); + clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); + check_gateway=1; + } + + if (chdlc_priv_area->route_status == ADD_ROUTE && + card->u.c.slarp_timer){ + + process_route(card); + check_gateway=1; + } + + if (chdlc_priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + + clear_bit(POLL_CRIT,&card->wandev.critical); } + +/*============================================================ + * trigger_chdlc_poll + * + * Description: + * Add a chdlc_poll() task into a tq_scheduler bh handler + * for a specific dlci/interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ +static void trigger_chdlc_poll (netdevice_t *dev) +{ + chdlc_private_area_t *chdlc_priv_area; + sdla_t *card; + + if (!dev) + return; + + if ((chdlc_priv_area = dev->priv)==NULL) + return; + + card = chdlc_priv_area->card; + + if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + #ifdef LINUX_2_4 + schedule_task(&chdlc_priv_area->poll_task); + #else + queue_task(&chdlc_priv_area->poll_task, &tq_scheduler); + #endif + return; +} + + +static void chdlc_poll_delay (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + trigger_chdlc_poll(dev); +} + + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ +#if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } +#else + disable_irq(card->hw.irq); +#endif +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ +#if defined(__SMP__) || defined(LINUX_2_4) + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +#else + enable_irq(card->hw.irq); +#endif +} + +//*********** TTY SECTION **************** +#if defined(LINUX_2_4) || defined(LINUX_2_1) + +static void wanpipe_tty_trigger_tx_irq(sdla_t *card) +{ + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; +} + +static void wanpipe_tty_trigger_poll(sdla_t *card) +{ + #ifdef LINUX_2_4 + schedule_task(&card->tty_task_queue); + #else + queue_task(&card->tty_task_queue, &tq_scheduler); + #endif +} + +static void tty_poll_task (void* data) +{ + sdla_t *card = (sdla_t*)data; + struct tty_struct *tty; + + if ((tty=card->tty)==NULL) + return; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup){ + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); + #if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tty->poll_wait); + #endif + return; +} + +static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) +{ + sdla_t *card; + unsigned long smp_flags; + + if (!tty || !tty->driver_data){ + return; + } + + card = (sdla_t*)tty->driver_data; + + if (!card) + return; + + printk(KERN_INFO "%s: Closing TTY Driver!\n", + card->devname); + + /* Sanity Check */ + if (!card->tty_open) + return; + + wanpipe_close(card); + if (--card->tty_open == 0){ + + lock_adapter_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + chdlc_disable_comm_shutdown(card); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + + if (card->tty_buf){ + kfree(card->tty_buf); + card->tty_buf=NULL; + } + + if (card->tty_rx){ + kfree(card->tty_rx); + card->tty_rx=NULL; + } + } + return; +} +static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) +{ + unsigned long smp_flags; + sdla_t *card; + + if (!tty){ + return -ENODEV; + } + + if (!tty->driver_data){ + int port; + port = MINOR(tty->device) - tty->driver.minor_start; + if ((port < 0) || (port >= NR_PORTS)) + return -ENODEV; + + tty->driver_data = WAN_CARD(port); + if (!tty->driver_data) + return -ENODEV; + } + + card = (sdla_t*)tty->driver_data; + + if (!card){ + lock_adapter_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + return -ENODEV; + } + + printk(KERN_INFO "%s: Opening TTY Driver!\n", + card->devname); + + if (card->tty_open == 0){ + lock_adapter_irq(&card->wandev.lock,&smp_flags); + card->tty=tty; + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + + if (!card->tty_buf){ + card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); + if (!card->tty_buf){ + card->tty_buf=NULL; + card->tty=NULL; + return -ENOMEM; + } + } + + if (!card->tty_rx){ + card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); + if (!card->tty_rx){ + /* Free the buffer above */ + kfree(card->tty_buf); + card->tty_buf=NULL; + card->tty=NULL; + return -ENOMEM; + } + } + } + + ++card->tty_open; + wanpipe_open(card); + return 0; +} + +static int wanpipe_tty_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + unsigned long smp_flags=0; + sdla_t *card=NULL; + + if (!tty){ + dbg_printk(KERN_INFO "NO TTY in Write\n"); + return -ENODEV; + } + + card = (sdla_t *)tty->driver_data; + + if (!card){ + dbg_printk(KERN_INFO "No Card in TTY Write\n"); + return -ENODEV; + } + + if (count > card->wandev.mtu){ + dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", + count,card->wandev.mtu); + return -EINVAL; + } + + if (card->wandev.state != WAN_CONNECTED){ + dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); + return -EINVAL; + } + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ + printk(KERN_INFO "%s: Critical in TTY Write\n", + card->devname); + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -EINVAL; + } + + if (from_user) { + + unsigned char *tmp_buf; + + if ((tmp_buf=card->tty_buf)==NULL){ + dbg_printk(KERN_INFO "No TTY BUF in Write\n"); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -ENOMEM; + } + + if (copy_from_user(tmp_buf,buf,count)){ + dbg_printk(KERN_INFO "%s: Failed to copy from user!\n", + card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -EINVAL; + } + + if (chdlc_send(card,(void*)tmp_buf,count)){ + dbg_printk(KERN_INFO "%s: Failed to send, retry later: user!\n", + card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + wanpipe_tty_trigger_tx_irq(card); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + return 0; + } + + }else{ + if (chdlc_send(card,(void*)buf,count)){ + dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", + card->devname); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + wanpipe_tty_trigger_tx_irq(card); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + return 0; + } + } + dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return count; +} + +static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) +{ + unsigned offset=0; + unsigned olen=len; + char fp=0; + struct tty_struct *tty; + int i; + + if (!card->tty_open){ + dbg_printk(KERN_INFO "%s: TTY not open during receive\n", + card->devname); + return; + } + + if ((tty=card->tty) == NULL){ + dbg_printk(KERN_INFO "%s: No TTY on receive\n", + card->devname); + return; + } + + if (!tty->driver_data){ + dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", + card->devname); + return; + } + + + if (card->u.c.async_mode){ + if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + + + if((addr + len) > card->u.c.rx_top + 1) { + offset = card->u.c.rx_top - addr + 1; + + sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); + + addr = card->u.c.rx_base; + len -= offset; + + tty->flip.char_buf_ptr+=offset; + tty->flip.count+=offset; + for (i=0;i<offset;i++){ + *tty->flip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + } + } + + sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); + + tty->flip.char_buf_ptr+=len; + card->tty->flip.count+=len; + for (i=0;i<len;i++){ + *tty->flip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + } + + tty->low_latency=1; + tty_flip_buffer_push(tty); + }else{ + if (!card->tty_rx){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Receive sync buffer not available!\n", + card->devname); + } + return; + } + + if (len > TTY_CHDLC_MAX_MTU){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + + + if((addr + len) > card->u.c.rx_top + 1) { + offset = card->u.c.rx_top - addr + 1; + + sdla_peek(&card->hw, addr, card->tty_rx, offset); + + addr = card->u.c.rx_base; + len -= offset; + } + sdla_peek(&card->hw, addr, card->tty_rx+offset, len); + if (tty->ldisc.receive_buf){ + tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen); + }else{ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: NO TTY Sync line discipline!\n", + card->devname); + } + } + } + + dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); + return; +} + +#if 0 +static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#endif + +static void wanpipe_tty_stop(struct tty_struct *tty) +{ + return; +} + +static void wanpipe_tty_start(struct tty_struct *tty) +{ + return; +} + +static int config_tty (sdla_t *card) +{ + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return -EINVAL; + } + }else{ + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC configuration!\n", + card->devname); + return -EINVAL; + } + } + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + + /* Enable communications */ + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + port_set_state(card, WAN_CONNECTING); + return 0; +} + + +static int change_speed(sdla_t *card, struct tty_struct *tty, + struct termios *old_termios) +{ + int baud, ret=0; + unsigned cflag; + int dbits,sbits,parity,handshaking; + + cflag = tty->termios->c_cflag; + + /* There is always one stop bit */ + sbits=WANOPT_ONE; + + /* Parity is defaulted to NONE */ + parity = WANOPT_NONE; + + handshaking=0; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dbits = 5; break; + case CS6: dbits = 6; break; + case CS7: dbits = 7; break; + case CS8: dbits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dbits = 8; break; + } + + /* One more stop bit should be supported, thus increment + * the number of stop bits Max=2 */ + if (cflag & CSTOPB) { + sbits = WANOPT_TWO; + } + if (cflag & PARENB) { + parity = WANOPT_EVEN; + } + if (cflag & PARODD){ + parity = WANOPT_ODD; + } + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + if (cflag & CRTSCTS) { + handshaking|=ASY_RTS_HS_FOR_RX; + } + + if (I_IGNPAR(tty)) + parity = WANOPT_NONE; + + if (I_IXOFF(tty)){ + handshaking|=ASY_XON_XOFF_HS_FOR_RX; + handshaking|=ASY_XON_XOFF_HS_FOR_TX; + } + + if (I_IXON(tty)){ + handshaking|=ASY_XON_XOFF_HS_FOR_RX; + handshaking|=ASY_XON_XOFF_HS_FOR_TX; + } + + if (card->u.c.async_mode){ + if (card->wandev.bps != baud) + ret=1; + card->wandev.bps = baud; + } + + if (card->u.c.async_mode){ + if (card->u.c.protocol_options != handshaking) + ret=1; + card->u.c.protocol_options = handshaking; + + if (card->u.c.tx_bits_per_char != dbits) + ret=1; + card->u.c.tx_bits_per_char = dbits; + + if (card->u.c.rx_bits_per_char != dbits) + ret=1; + card->u.c.rx_bits_per_char = dbits; + + if (card->u.c.stop_bits != sbits) + ret=1; + card->u.c.stop_bits = sbits; + + if (card->u.c.parity != parity) + ret=1; + card->u.c.parity = parity; + + card->u.c.break_timer = 50; + card->u.c.inter_char_timer = 10; + card->u.c.rx_complete_length = 100; + card->u.c.xon_char = 0xFE; + }else{ + card->u.c.protocol_options = HDLC_STREAMING_MODE; + } + + return ret; +} + + +static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + sdla_t *card; + int err=1; + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + + if (!card) + return; + + if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ + unsigned long smp_flags; + + if (card->u.c.comm_enabled){ + lock_adapter_irq(&card->wandev.lock,&smp_flags); + chdlc_disable_comm_shutdown(card); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + } + lock_adapter_irq(&card->wandev.lock,&smp_flags); + err = config_tty(card); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + if (card->u.c.async_mode){ + printk(KERN_INFO "%s: TTY Async Configuration:\n" + " Baud =%i\n" + " Handshaking =%s\n" + " Tx Dbits =%i\n" + " Rx Dbits =%i\n" + " Parity =%s\n" + " Stop Bits =%i\n", + card->devname, + card->wandev.bps, + opt_decode[card->u.c.protocol_options], + card->u.c.tx_bits_per_char, + card->u.c.rx_bits_per_char, + p_decode[card->u.c.parity] , + card->u.c.stop_bits); + }else{ + printk(KERN_INFO "%s: TTY Sync Configuration:\n" + " Baud =%i\n" + " Protocol =HDLC_STREAMING\n", + card->devname,card->wandev.bps); + } + if (!err){ + port_set_state(card,WAN_CONNECTED); + }else{ + port_set_state(card,WAN_DISCONNECTED); + } + } + return; +} + +static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + sdla_t *card; + unsigned long smp_flags=0; + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + + if (!card) + return; + + if (card->wandev.state != WAN_CONNECTED) + return; + + if(card->hw.type != SDLA_S514) + s508_lock(card,&smp_flags); + + if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ + + wanpipe_tty_trigger_tx_irq(card); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + return; + } + + if (chdlc_send(card,(void*)&ch,1)){ + wanpipe_tty_trigger_tx_irq(card); + dbg_printk("%s: Failed to TX char!\n",card->devname); + } + + dbg_printk("%s: Char TX OK\n",card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return; +} + +static void wanpipe_tty_flush_chars(struct tty_struct *tty) +{ + return; +} + +static void wanpipe_tty_flush_buffer(struct tty_struct *tty) +{ + if (!tty) + return; + + wake_up_interruptible(&tty->write_wait); +#if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + return; +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) +{ + return; +} + + +static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) +{ + return 0; +} + + +static int wanpipe_tty_write_room(struct tty_struct *tty) +{ + sdla_t *card; + + printk(KERN_INFO "TTY Write Room\n"); + + if (!tty){ + return 0; + } + + card = (sdla_t *)tty->driver_data; + if (!card) + return 0; + + if (card->wandev.state != WAN_CONNECTED) + return 0; + + return SEC_MAX_NO_DATA_BYTES_IN_FRAME; +} + + +static int set_modem_status(sdla_t *card, unsigned char data) +{ + CHDLC_MAILBOX_STRUCT *mb = card->mbox; + int err; + + mb->buffer_length=1; + mb->command=SET_MODEM_STATUS; + mb->data[0]=data; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + + return err; +} + +static void wanpipe_tty_hangup(struct tty_struct *tty) +{ + sdla_t *card; + unsigned long smp_flags; + + printk(KERN_INFO "TTY Hangup!\n"); + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + if (!card) + return; + + lock_adapter_irq(&card->wandev.lock,&smp_flags); + set_modem_status(card,0); + unlock_adapter_irq(&card->wandev.lock,&smp_flags); + return; +} + +static void wanpipe_tty_break(struct tty_struct *tty, int break_state) +{ + return; +} + +static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + return; +} + +static void wanpipe_tty_throttle(struct tty_struct * tty) +{ + return; +} + +static void wanpipe_tty_unthrottle(struct tty_struct * tty) +{ + return; +} + +int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + return 0; +} + +/* + * The serial driver boot-time initialization code! + */ +int wanpipe_tty_init(sdla_t *card) +{ + struct serial_state * state; + + /* Initialize the tty_driver structure */ + + if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ + printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", + card->devname,card->tty_minor); + return -EINVAL; + } + + if (WAN_CARD(card->tty_minor)){ + printk(KERN_INFO "%s: TTY Minor %i, already in use\n", + card->devname,card->tty_minor); + return -EBUSY; + } + + if (tty_init_cnt==0){ + + printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", + card->devname, + card->u.c.async_mode ? "ASYNC" : "SYNC", + WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); + + tty_driver_mode = card->u.c.async_mode; + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "wanpipe_tty"; + serial_driver.name = "ttyW"; + serial_driver.major = WAN_TTY_MAJOR; + serial_driver.minor_start = WAN_TTY_MINOR; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = wanpipe_tty_open; + serial_driver.close = wanpipe_tty_close; + serial_driver.write = wanpipe_tty_write; + + serial_driver.put_char = wanpipe_tty_put_char; + serial_driver.flush_chars = wanpipe_tty_flush_chars; + serial_driver.write_room = wanpipe_tty_write_room; + serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; + serial_driver.flush_buffer = wanpipe_tty_flush_buffer; + //serial_driver.ioctl = wanpipe_tty_ioctl; + serial_driver.throttle = wanpipe_tty_throttle; + serial_driver.unthrottle = wanpipe_tty_unthrottle; + serial_driver.send_xchar = wanpipe_tty_send_xchar; + serial_driver.set_termios = wanpipe_tty_set_termios; + serial_driver.stop = wanpipe_tty_stop; + serial_driver.start = wanpipe_tty_start; + serial_driver.hangup = wanpipe_tty_hangup; + serial_driver.break_ctl = wanpipe_tty_break; + serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; + serial_driver.read_proc = wanpipe_tty_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cuw"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)){ + printk(KERN_INFO "%s: Failed to register serial driver!\n", + card->devname); + } + + if (tty_register_driver(&callout_driver)){ + printk(KERN_INFO "%s: Failed to register callout driver!\n", + card->devname); + } + + } + + + /* The subsequent ports must comply to the initial configuration */ + if (tty_driver_mode != card->u.c.async_mode){ + printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", + card->devname); + printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", + card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); + return -EINVAL; + } + + tty_init_cnt++; + + printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", + card->devname, + tty_driver_mode ? "ASYNC" : "SYNC", + card->tty_minor); + + tty_card_map[card->tty_minor] = card; + state = &rs_table[card->tty_minor]; + + state->magic = SSTATE_MAGIC; + state->line = 0; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = card->wandev.irq; + + card->tty_task_queue.routine = tty_poll_task; + card->tty_task_queue.data = (void*)card; + return 0; +} + +#endif + /****** End ****************************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c --- v2.4.3/linux/drivers/net/wan/sdla_fr.c Tue Mar 6 19:44:36 2001 +++ linux/drivers/net/wan/sdla_fr.c Thu Apr 12 12:11:39 2001 @@ -4,14 +4,43 @@ * Author(s): Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * 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. * ============================================================================ -* Feb 28, 2000 Jeff Garzik o softnet updates +* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels +* Nov 15, 2000 David Rokavarg +* Nenad Corbic o Added frame relay bridging support. +* Original code from Mark Wells and Kristian Hoffmann has +* been integrated into the frame relay driver. +* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. +* Tcpdump doesn't support Frame Relay inteface +* types, to fix this true type option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. +* Moved the if_header into the if_send() routine. +* The if_header() was breaking the libpcap +* support. i.e. support for tcpdump, ethereal ... +* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure +* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. +* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface +* when the channel gets disconnected. +* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate +* interface setups. +* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove +* new dlcis/interfaces. +* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support +* Mar 13, 2000 Nenad Corbic o Added new socket API support. +* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. +* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels +* * Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function * o Removed the ARP support. This has to be done * in the next version. @@ -109,12 +138,12 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include <linux/config.h> +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ @@ -123,14 +152,29 @@ #include <linux/time.h> /* for do_gettimeofday */ #include <linux/in.h> /* sockaddr_in */ #include <linux/inet.h> /* in_ntoa(), etc... */ -#include <asm/uaccess.h> -#include <linux/inetdevice.h> +#include <asm/errno.h> + #include <linux/ip.h> -#include <net/route.h> /* Dynamic Route Creation */ #include <linux/if.h> -#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ - +#include <linux/if_wanpipe_common.h> /* Wanpipe Socket */ +#include <linux/if_wanpipe.h> + +#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> + #include <linux/inetdevice.h> + #include <linux/netdevice.h> + +#else + #include <asm/segment.h> +#endif + +#include <net/route.h> /* Dynamic Route Creation */ +#include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ +#include <linux/random.h> + /****** Defines & Macros ****************************************************/ #define MAX_CMD_RETRY 10 /* max number of firmware retries */ @@ -151,25 +195,20 @@ #define CIR_ENABLED 0x00 #define CIR_DISABLED 0x01 -#define WANPIPE 0x00 -#define API 0x01 #define FRAME_RELAY_API 1 - -#define TX_TIMEOUT (5*HZ) +#define MAX_BH_BUFF 10 /* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) /****** Data Structures *****************************************************/ -/* This is an extention of the 'struct net_device' we create for each network +/* This is an extention of the 'struct device' we create for each network * interface to keep the rest of channel-specific data. */ typedef struct fr_channel { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + wanpipe_common_t common; char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ unsigned dlci_configured ; /* check whether configured or not */ unsigned cir_status; /* check whether CIR enabled or not */ @@ -183,7 +222,6 @@ unsigned long router_start_time;/* Router start time in seconds */ unsigned long tick_counter; /* counter for transmit time out */ char dev_pending_devtint; /* interface pending dev_tint() */ - char state; /* channel state */ void *dlci_int_interface; /* pointer to the DLCI Interface */ unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ @@ -192,19 +230,52 @@ sdla_t *card; /* -> owner */ unsigned route_flag; /* Add/Rem dest addr in route tables */ unsigned inarp; /* Inverse Arp Request status */ + unsigned char inarp_ready; /* Ready to send requests */ int inarp_interval; /* Time between InArp Requests */ unsigned long inarp_tick; /* InArp jiffies tick counter */ + unsigned char interface_down; /* Bring interface down on disconnect */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) struct net_device_stats ifstats; /* interface statistics */ + #else + struct enet_statistics ifstats; + #endif if_send_stat_t drvstats_if_send; rx_intr_stat_t drvstats_rx_intr; pipe_mgmt_stat_t drvstats_gen; - - unsigned char usedby; /* Used by WANPIPE or API */ - unsigned long router_up_time; unsigned short transmit_length; - char transmit_buffer[FR_MAX_NO_DATA_BYTES_IN_FRAME]; + struct sk_buff *delay_skb; + + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; + #endif + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct fr_poll_task; + struct timer_list fr_arp_timer; + + u32 ip_local; + u32 ip_remote; + u8 config_dlci; + u32 unconfig_dlci; + + /* Whether this interface should be setup as a gateway. + * Used by dynamic route setup code */ + u8 gateway; + + /* True interface type */ + u8 true_if_encoding; + u8 fr_header[FR_HEADER_LEN]; + char fr_header_len; + } fr_channel_t; /* Route Flag options */ @@ -212,6 +283,7 @@ #define ADD_ROUTE 0x01 #define ROUTE_ADDED 0x02 #define REMOVE_ROUTE 0x03 +#define ARP_REQ 0x04 /* inarp options */ #define INARP_NONE 0x00 @@ -221,6 +293,10 @@ /* reasons for enabling the timer interrupt on the adapter */ #define TMR_INT_ENABLED_UDP 0x01 #define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_ARP 0x04 +#define TMR_INT_ENABLED_UPDATE_STATE 0x08 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_UNCONFIG 0x20 typedef struct dlci_status @@ -248,7 +324,6 @@ /* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; -extern int ip_rt_ioctl(unsigned int, void *); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -256,27 +331,43 @@ * interrupt test routine */ static int Intr_test_counter; + /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ static int update(wan_device_t *wandev); -static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf); -static int del_if(wan_device_t *wandev, struct net_device *dev); +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); +static void disable_comm (sdla_t *card); /* WANPIPE-specific entry points */ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); /* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); -static int if_rebuild_hdr(struct sk_buff *skb); -static int if_send(struct sk_buff *skb, struct net_device *dev); -static void if_tx_timeout (struct net_device *dev); -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int if_init(netdevice_t *dev); +static int if_open(netdevice_t *dev); +static int if_close(netdevice_t *dev); + + +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static int if_rebuild_hdr (struct sk_buff *skb); +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb); +#endif + +static int if_send(struct sk_buff *skb, netdevice_t *dev); +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats *if_stats(netdevice_t *dev); +#else +static struct enet_statistics* if_stats (netdevice_t* dev); +#endif /* Interrupt handlers */ static void fr_isr(sdla_t *card); @@ -292,7 +383,7 @@ static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); static int fr_comm_enable(sdla_t *card); -static int fr_comm_disable(sdla_t *card); +static void fr_comm_disable(sdla_t *card); static int fr_get_err_stats(sdla_t *card); static int fr_get_stats(sdla_t *card); static int fr_add_dlci(sdla_t *card, int dlci); @@ -301,6 +392,13 @@ static int fr_issue_isf(sdla_t *card, int isf); static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, void *buf); +static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, + void *buf,unsigned char hdr_len); +static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); + +static int check_dlci_config (sdla_t *card, fr_channel_t *chan); +static void initialize_rx_tx_buffers (sdla_t *card); + /* Firmware asynchronous event handlers */ static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); @@ -308,9 +406,9 @@ static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); /* Miscellaneous functions */ -static int update_chan_state(struct net_device *dev); -static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t *card, unsigned dlci); +static int update_chan_state(netdevice_t *dev); +static void set_chan_state(netdevice_t *dev, int state); +static netdevice_t *find_channel(sdla_t *card, unsigned dlci); static int is_tx_ready(sdla_t *card, fr_channel_t *chan); static unsigned int dec_to_uint(unsigned char *str, int len); static int reply_udp( unsigned char *data, unsigned int mbox_len ); @@ -319,14 +417,38 @@ static void init_chan_statistics( fr_channel_t* chan ); static void init_global_statistics( sdla_t* card ); static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); -static void setup_for_delayed_transmit(struct net_device* dev, void* buf, - unsigned len); +static int setup_for_delayed_transmit(netdevice_t* dev, struct sk_buff *skb); + +netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *); +static int check_tx_status(sdla_t *, netdevice_t *); + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +/* Frame Relay Socket API */ +static void trigger_fr_bh (fr_channel_t *); +static void fr_bh (netdevice_t *); +static int fr_bh_cleanup (netdevice_t *); +static int bh_enqueue (netdevice_t *, struct sk_buff *); +#endif + +static void trigger_fr_poll (netdevice_t *); +static void fr_poll (netdevice_t *); +//static void add_gateway (netdevice_t *); + +static void trigger_unconfig_fr (netdevice_t *dev); +static void unconfig_fr (sdla_t *); + +static void trigger_config_fr (sdla_t *); +static void config_fr (sdla_t *); /* Inverse ARP and Dynamic routing functions */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t *dev); int is_arp(void *buf); -int send_inarp_request(sdla_t *card, struct net_device *dev); +int send_inarp_request(sdla_t *card, netdevice_t *dev); + +static void trigger_fr_arp (netdevice_t *); +static void fr_arp (unsigned long data); + /* Udp management functions */ static int process_udp_mgmt_pkt(sdla_t *card); @@ -346,6 +468,7 @@ void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); unsigned short calc_checksum (char *, int); +static int setup_fr_header(struct sk_buff** skb, netdevice_t* dev, char op_mode); /****** Public Functions ****************************************************/ @@ -366,15 +489,20 @@ { int err; + fr508_flags_t* flags; union { char str[80]; fr_conf_t cfg; } u; + fr_buf_info_t* buf_info; int i; + + printk(KERN_INFO "\n"); + /* Verify configuration ID */ if (conf->config_id != WANCONFIG_FR) { @@ -403,6 +531,8 @@ return -EINVAL; } + flags = card->flags; + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work @@ -429,7 +559,7 @@ memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); /* Configure adapter firmware */ - + u.cfg.mtu = conf->mtu; u.cfg.kbps = conf->bps / 1000; @@ -546,9 +676,7 @@ (void*)(buf_info->rse_base + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + card->hw.dpmbase); - } - - else { + }else{ buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); card->rxmb = (void*)(buf_info->rse_next - @@ -582,6 +710,8 @@ card->wandev.state = WAN_DISCONNECTED; card->wandev.ttl = conf->ttl; card->wandev.udp_port = conf->udp_port; + card->disable_comm = &disable_comm; + card->u.f.arp_dev = NULL; /* Intialize global statistics for a card */ init_global_statistics( card ); @@ -593,11 +723,13 @@ card->intr_mode = INTR_TEST_MODE; err = intr_test( card ); + printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", + card->devname,err,Intr_test_counter); + if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk( - "%s: Interrupt Test Failed, Counter: %i\n", + printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", card->devname, Intr_test_counter); - printk( "Please choose another interrupt\n"); + printk(KERN_ERR "Please choose another interrupt\n"); err = -EIO; return err; } @@ -606,6 +738,32 @@ card->devname, Intr_test_counter); + /* Apr 28 2000. Nenad Corbic + * Enable commnunications here, not in if_open or new_if, since + * interfaces come down when the link is disconnected. + */ + + /* If you enable comms and then set ints, you get a Tx int as you + * perform the SET_INT_TRIGGERS command. So, we only set int + * triggers and then adjust the interrupt mask (to disable Tx ints) + * before enabling comms. + */ + if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | + FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , + card->wandev.mtu, 0)) { + return -EIO; + } + + flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); + + if (fr_comm_enable(card)) { + return -EIO; + } + wanpipe_set_state(card, WAN_CONNECTED); + spin_lock_init(&card->u.f.if_send_lock); + + printk(KERN_INFO "\n"); + return 0; } @@ -627,9 +785,6 @@ if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_bit(1, (void*)&wandev->critical)) - return -EAGAIN; - card = wandev->private; flags = card->flags; @@ -646,6 +801,7 @@ return -EAGAIN; } } + return 0; } @@ -661,16 +817,17 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; fr_channel_t* chan; int dlci = 0; int err = 0; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", + printk(KERN_INFO "%s: Invalid interface name!\n", card->devname); return -EINVAL; } @@ -684,7 +841,7 @@ memset(chan, 0, sizeof(fr_channel_t)); strcpy(chan->name, conf->name); chan->card = card; - + /* verify media address */ if (is_digit(conf->addr[0])) { @@ -697,38 +854,92 @@ } else { printk(KERN_ERR - "%s: invalid DLCI %u on interface %s!\n", + "%s: Invalid DLCI %u on interface %s!\n", wandev->name, dlci, chan->name); err = -EINVAL; } } else { printk(KERN_ERR - "%s: invalid media address on interface %s!\n", + "%s: Invalid media address on interface %s!\n", wandev->name, chan->name); err = -EINVAL; } - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if(strcmp(conf->usedby, "WANPIPE") == 0){ - printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", - wandev->name, chan->name); - chan->usedby = WANPIPE; + if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ + printk(KERN_INFO + "%s: Enabling, true interface type encoding.\n", + card->devname); + } + + + + /* Setup wanpipe as a router (WANPIPE) even if it is + * a bridged DLCI, or as an API + */ + if (strcmp(conf->usedby, "WANPIPE") == 0 || + strcmp(conf->usedby, "BRIDGE") == 0 || + strcmp(conf->usedby, "BRIDGE_N") == 0){ + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + chan->common.usedby = WANPIPE; + + printk(KERN_INFO "%s: Running in WANPIPE mode.\n", + card->devname); + + }else if(strcmp(conf->usedby, "BRIDGE") == 0){ + + chan->common.usedby = BRIDGE; + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname); + #else + printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n", + card->devname); + err = -EPROTONOSUPPORT; + #endif + + }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ + + chan->common.usedby = BRIDGE_NODE; + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname); + #else + printk(KERN_INFO "%s: WANPIPE Bridging mode not supported in 2.0.X kernels.\n", + card->devname); + err = -EPROTONOSUPPORT; + #endif + } + + if (!err){ + /* Dynamic interface configuration option. + * On disconnect, if the options is selected, + * the interface will be brought down */ + if (conf->if_down == WANOPT_YES){ + set_bit(DYN_OPT_ON,&chan->interface_down); + printk(KERN_INFO + "%s: Dynamic interface configuration enabled.\n", + card->devname); + } + } } else if(strcmp(conf->usedby, "API") == 0){ -#ifdef FRAME_RELAY_API - chan->usedby = API; - printk(KERN_INFO "%s: Running in API mode %s\n", - wandev->name, chan->name); -#else - printk(KERN_INFO "%s: API Mode is not supported !\n", + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->common.usedby = API; + printk(KERN_INFO "%s: Running in API mode.\n", wandev->name); - printk(KERN_INFO - "%s: API patch can be obtained from Sangoma Tech.\n", - wandev->name); + #else + printk(KERN_INFO "%s: The API Mode is not supported for" + "kernels lower than 2.2.X !\n", + wandev->name); + printk(KERN_INFO "%s: Please upgrade to a 2.2.X kernel for the API support\n", + wandev->name); err = -EINVAL; -#endif + #endif } if (err) { @@ -737,8 +948,6 @@ return err; } - card->u.f.dlci_to_dev_map[dlci] = dev; - /* place cir,be,bc and other channel specific information into the * chan structure */ @@ -774,20 +983,24 @@ chan->mc = conf->mc; - /* FIXME: ARP is not supported by this frame relay verson */ if (conf->inarp == WANOPT_YES){ - printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support ARPs\n", + #if defined(LINUX_2_1) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); + chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; + #else + printk(KERN_INFO "%s: Warning, Inverse ARP Support not available for 2.0.X kernels!\n", card->devname); - - //chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; - //chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; - kfree(chan); - return -EINVAL; + chan->inarp = INARP_NONE; + chan->inarp_interval = 10; + #endif }else{ + printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); chan->inarp = INARP_NONE; chan->inarp_interval = 10; } + chan->dlci_configured = DLCI_NOT_CONFIGURED; @@ -814,64 +1027,102 @@ chan->transmit_length = 0; /* prepare network device data space for registration */ - strcpy(dev->name, chan->name); + #ifdef LINUX_2_4 + strcpy(dev->name,chan->name); + #else + dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", chan->name); + #endif + dev->init = &if_init; dev->priv = chan; - - /* Enable Interrupts and Communications */ - if (!wandev->new_if_cnt){ - fr508_flags_t* flags = card->flags; - - wandev->new_if_cnt++; - - /* - If you enable comms and then set ints, you get a Tx int as you - perform the SET_INT_TRIGGERS command. So, we only set int - triggers and then adjust the interrupt mask (to disable Tx ints) - before enabling comms. - */ - if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | - FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , - card->wandev.mtu, 0)) { - kfree(chan); - return -EIO; - } - - flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); - - if (fr_comm_enable(card)) { - kfree(chan); - return -EIO; - } - wanpipe_set_state(card, WAN_CONNECTED); + /* Initialize FR Polling Task Queue + * We need a poll routine for each network + * interface. + */ + #ifndef LINUX_2_4 + chan->fr_poll_task.next = NULL; + #endif + chan->fr_poll_task.sync = 0; + chan->fr_poll_task.routine = (void *)(void *)fr_poll; + chan->fr_poll_task.data = dev; + + init_timer(&chan->fr_arp_timer); + chan->fr_arp_timer.data=(unsigned long)dev; + chan->fr_arp_timer.function = fr_arp; + + wandev->new_if_cnt++; + + /* Tells us that if this interface is a + * gateway or not */ + if ((chan->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,dev->name); + } + + /* M. Grant Patch Apr 28 2000 + * Disallow duplicate dlci configurations. */ + if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { + kfree(chan); + return -EBUSY; } + /* Configure this dlci at a later date, when + * the interface comes up. i.e. when if_open() + * executes */ + set_bit(0,&chan->config_dlci); + + printk(KERN_INFO "\n"); + return 0; } /*============================================================================ * Delete logical channel. */ -static int del_if (wan_device_t* wandev, struct net_device* dev) +static int del_if (wan_device_t* wandev, netdevice_t* dev) { - sdla_t *card = wandev->private; + fr_channel_t* chan = dev->priv; + unsigned long smp_flags=0; - /* Execute shutdown very first time we enter del_if */ + /* This interface is dead, make sure the + * ARP timer is stopped */ + del_timer(&chan->fr_arp_timer); + + /* If we are a NODE, we must unconfigure this DLCI + * Trigger an unconfigure command that will + * be executed in timer interrupt. We must wait + * for the command to complete. */ + trigger_unconfig_fr(dev); + + lock_adapter_irq(&wandev->lock, &smp_flags); + wandev->new_if_cnt--; + unlock_adapter_irq(&wandev->lock, &smp_flags); - if (!wandev->del_if_cnt) { - wandev->del_if_cnt++; - wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0, 0); - fr_comm_disable(card); - } + return 0; +} - if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } - return 0; +/*===================================================================== + * disable_comm + * + * Description: + * Disable communications. + * This code runs in shutdown (sdlamain.c) + * under critical flag. Therefore it is not + * necessary to set a critical flag here + * + * Usage: + * Commnunications are disabled only on a card + * shutdown. + */ + +static void disable_comm (sdla_t *card) +{ + printk(KERN_INFO "%s: Disabling Communications!\n", + card->devname); + fr_comm_disable(card); } /****** WANPIPE-specific entry points ***************************************/ @@ -886,6 +1137,8 @@ int err, len; fr_cmd_t cmd; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) return -EFAULT; @@ -916,6 +1169,43 @@ return -EFAULT; return 0; +#else + if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(fr_cmd_t))) + return -EFAULT; + + memcpy_fromfs((void*)&cmd, u_cmd, sizeof(cmd)); + + if (cmd.length) { + + if (!u_data || verify_area(VERIFY_READ, u_data, cmd.length)) + return -EFAULT; + } + + /* execute command */ + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + + if (cmd.length) + memcpy_fromfs((void*)&mbox->data, u_data, cmd.length); + + if (sdla_exec(mbox)) + err = mbox->cmd.result; + + else return -EIO; + } while (err && retry-- && fr_event(card, err, mbox)); + + /* return result */ + memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t)); + len = mbox->cmd.length; + + if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)) + memcpy_tofs(u_data, (void*)&mbox->data, len); + + return 0; + +#endif + } /****** Network Device Interface ********************************************/ @@ -927,44 +1217,83 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init (struct net_device* dev) +static int if_init (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; wan_device_t* wandev = &card->wandev; + #ifdef LINUX_2_0 + int i; + #endif /* Initialize device driver entry points */ dev->open = &if_open; dev->stop = &if_close; - dev->hard_header = &if_header; + dev->hard_header = NULL; dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; + #ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + #endif + + if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ + + #ifdef LINUX_2_0 + dev->family = AF_INET; + #endif + /* Initialize media-specific parameters */ + if (chan->true_if_encoding){ + dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ + }else{ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + } + + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; - /* Initialize media-specific parameters */ - dev->type = ARPHRD_DLCI; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - - /* Enable Multicast addressing */ - if (chan->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } + /* Enable Multicast addressing */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } - dev->mtu = wandev->mtu - FR_HEADER_LEN; - /* For an API, the maximum number of bytes that the stack will pass - to the driver is (dev->mtu + dev->hard_header_len). So, adjust the - mtu so that a frame of maximum size can be transmitted by the API. - */ - if(chan->usedby == API) { - dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); - } - - dev->hard_header_len = FR_HEADER_LEN;/* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short*)dev->dev_addr = htons(chan->dlci); + dev->mtu = wandev->mtu - FR_HEADER_LEN; + /* For an API, the maximum number of bytes that the stack will pass + to the driver is (dev->mtu + dev->hard_header_len). So, adjust the + mtu so that a frame of maximum size can be transmitted by the API. + */ + if(chan->common.usedby == API) { + dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); + } + + dev->hard_header_len = FR_HEADER_LEN;/* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = htons(chan->dlci); + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) + dev_init_buffers(dev); + #else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); + #endif + + }else{ + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + } + /* Initialize hardware parameters (just for reference) */ dev->irq = wandev->irq; dev->dma = wandev->dma; @@ -972,13 +1301,6 @@ dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - - /* Initialize socket buffers */ - dev_init_buffers(dev); - - set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -989,60 +1311,51 @@ * * Return 0 if O.k. or errno. */ -static int if_open (struct net_device* dev) +static int if_open (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; int err = 0; struct timeval tv; - if (netif_running(dev)) - return -EBUSY; /* only one open is allowed */ - - if (test_and_set_bit(1, (void*)&card->wandev.critical)) - return -EAGAIN; - - - /* If signalling is set to NO, then setup - * DLCI addresses right away. Don't have to wait for - * link to connect. - */ - if (card->wandev.signalling == WANOPT_NO){ - printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", - card->wandev.name); - if (fr_init_dlci(card,chan)){ - return -EAGAIN; - } - } - - if (card->wandev.station == WANOPT_CPE) { - - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - - } else { /* FR switch: activate DLCI(s) */ - - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ + if (is_dev_running(dev)) + return -EBUSY; - fr_add_dlci(card, chan->dlci); - fr_activate_dlci(card, chan->dlci); - } + #if defined(LINUX_2_1) || defined(LINUX_2_4) + /* Initialize the task queue */ + chan->tq_working=0; + + #ifndef LINUX_2_4 + chan->common.wanpipe_task.next = NULL; + #endif + chan->common.wanpipe_task.sync = 0; + chan->common.wanpipe_task.routine = (void *)(void *)fr_bh; + chan->common.wanpipe_task.data = dev; + + /* Allocate and initialize BH circular buffer */ + chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); + memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); + atomic_set(&chan->bh_buff_used, 0); + #endif + #ifdef LINUX_2_4 netif_start_queue(dev); + #else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + #endif + wanpipe_open(card); - update_chan_state(dev); do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; - clear_bit(1, (void*)&card->wandev.critical); + + if (test_bit(0,&chan->config_dlci)){ + trigger_config_fr (card); + }else if (chan->inarp == INARP_REQUEST){ + trigger_fr_arp(dev); + } + return err; } @@ -1051,61 +1364,42 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ -static int if_close (struct net_device* dev) +static int if_close (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (test_and_set_bit(1, (void*)&card->wandev.critical)) - return -EAGAIN; + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } - netif_stop_queue(dev); + stop_net_queue(dev); + #ifndef LINUX_2_4 + dev->start=0; + #endif wanpipe_close(card); - if (card->wandev.station == WANOPT_NODE) { - fr_delete_dlci (card,chan->dlci); - } - clear_bit(1, (void*)&card->wandev.critical); return 0; } /*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header (struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len) -{ - int hdr_len = 0; - - skb->protocol = type; - hdr_len = wanrouter_encapsulate(skb, dev); - - if (hdr_len < 0) { - hdr_len = 0; - skb->protocol = 0; - } - skb_push(skb, 1); - skb->data[0] = Q922_UI; - ++hdr_len; - return hdr_len; -} - -/*============================================================================ * Re-build media header. * * Return: 1 physical address resolved. * 0 physical address not resolved */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr (struct sk_buff* skb) { - struct net_device *dev = skb->dev; +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb) +{ +#endif + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + netdevice_t *dev = skb->dev; + #endif fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -1114,13 +1408,14 @@ return 1; } - +#ifdef LINUX_2_4 /*============================================================================ * Handle transmit timeout event from netif watchdog */ -static void if_tx_timeout (struct net_device *dev) +static void if_tx_timeout (netdevice_t *dev) { fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect @@ -1131,12 +1426,13 @@ chan->drvstats_if_send.if_send_tbusy++; ++chan->ifstats.collisions; - printk (KERN_INFO "%s: Transmit timed out\n", chan->name); + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); chan->drvstats_if_send.if_send_tbusy_timeout++; netif_wake_queue (dev); } - +#endif /*============================================================================ * Send a packet on a network interface. @@ -1154,23 +1450,28 @@ * Notes: * 1. This routine is called either by the protocol stack or by the "net * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. + * + * 2. Using the start_net_queue() and stop_net_queue() MACROS + * will inhibit further transmit requests from the protocol stack + * and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff* skb, struct net_device* dev) +static int if_send (struct sk_buff* skb, netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; int err; unsigned char *sendpacket; fr508_flags_t* adptr_flags = card->flags; - int udp_type, send_data; + int udp_type, delay_tx_queued=0; unsigned long smp_flags=0; - void* data; - unsigned len; + unsigned char attr = 0; chan->drvstats_if_send.if_send_entry++; + #ifdef LINUX_2_4 + netif_stop_queue(dev); + #endif + if (skb == NULL) { /* if we get here, some higher layer thinks we've missed an * tx-done interrupt. @@ -1178,7 +1479,19 @@ printk(KERN_INFO "%s: interface %s got kicked!\n", card->devname, dev->name); chan->drvstats_if_send.if_send_skb_null ++; - netif_wake_queue(dev); + + wake_net_dev(dev); + return 0; + } + + /* If a peripheral task is running just drop packets */ + if (test_bit(PERI_CRIT, &card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", + card->devname); + + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); return 0; } @@ -1187,23 +1500,58 @@ ensure that the transmit interrupt does not reset the 'tbusy' flag just before we set it, as this will result in a "transmit timeout". */ - set_bit(2, (void*)&card->wandev.critical); + set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); if(chan->transmit_length) { - netif_stop_queue(dev); - chan->tick_counter = jiffies; - clear_bit(2, (void*)&card->wandev.critical); + stop_net_queue(dev); + chan->tick_counter = jiffies; + clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); return 1; } - clear_bit(2, (void*)&card->wandev.critical); - - data = skb->data; + clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); + + #ifndef LINUX_2_4 + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + chan->drvstats_if_send.if_send_tbusy++; + ++chan->ifstats.collisions; + + if ((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + printk(KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, chan->name); + chan->drvstats_if_send.if_send_tbusy_timeout ++; + dev->tbusy = 0; + } + #endif + + + /* Move the if_header() code to here. By inserting frame + * relay header in if_header() we would break the + * tcpdump and other packet sniffers */ + chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby); + if (chan->fr_header_len < 0 ){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; + } + sendpacket = skb->data; - len = skb->len; udp_type = udp_pkt_type(skb, card); if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, chan->dlci)) { adptr_flags->imask |= FR_INTR_TIMER; if (udp_type == UDP_FPIPE_TYPE){ @@ -1211,61 +1559,92 @@ if_send_PIPE_request ++; } } + start_net_queue(dev); return 0; } - if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) { - //FIXME: increment some error statistic - dev_kfree_skb(skb); - return 0; - } - //FIXME: can we do better than sendpacket[2]? - if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) { + if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { + /* check to see if the source IP address is a broadcast or */ /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)) - return 0; + if(chk_bcast_mcast_addr(card, dev, skb)){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb, FREE_WRITE); + start_net_queue(dev); + return 0; + } } - /* Lock the 508 card: SMP Supported */ + + /* Lock the S514/S508 card: SMP Supported */ s508_s514_lock(card,&smp_flags); - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + chan->drvstats_if_send.if_send_critical_non_ISR ++; chan->ifstats.tx_dropped ++; - printk(KERN_INFO "%s Critical in IF_SEND %02X\n", - card->devname, card->wandev.critical); - dev_kfree_skb(skb); - /* Unlock the 508 card */ - s508_s514_unlock(card,&smp_flags); - return 0; + printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", + card->devname); + goto if_send_start_and_exit; } - + + /* API packet check: minimum packet size must be greater than + * 16 byte API header */ + if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + + goto if_send_start_and_exit; + + }else{ + /* During API transmission, get rid of the API header */ + if (chan->common.usedby == API) { + api_tx_hdr_t* api_tx_hdr; + api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; + attr = api_tx_hdr->attr; + skb_pull(skb,sizeof(api_tx_hdr_t)); + } + } + if (card->wandev.state != WAN_CONNECTED) { chan->drvstats_if_send.if_send_wan_disconnected ++; ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } else if (chan->state != WAN_CONNECTED) { + } else if (chan->common.state != WAN_CONNECTED) { chan->drvstats_if_send.if_send_dlci_disconnected ++; - /* Critical area on 514, since disabl_irq is not used - * thus, interrupt would execute a command at - * the same time as if_send. - */ - set_bit(1, (void*)&card->wandev.critical); - update_chan_state(dev); - clear_bit(1, (void*)&card->wandev.critical); + + /* Update the DLCI state in timer interrupt */ + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; + adptr_flags->imask |= FR_INTR_TIMER; + ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - + } else if (!is_tx_ready(card, chan)) { - setup_for_delayed_transmit(dev, data, len); + /* No tx buffers available, store for delayed transmit */ + if (!setup_for_delayed_transmit(dev, skb)){ + set_bit(1,&delay_tx_queued); + } chan->drvstats_if_send.if_send_no_bfrs++; - } else { - send_data = 1; + + } else if (!skb->protocol) { + /* No protocols drop packet */ + chan->drvstats_if_send.if_send_protocol_error ++; + ++card->wandev.stats.tx_errors; + + } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ + /* We are trying to send an ARP Packet, block IP data until + * ARP is sent */ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else { //FIXME: IPX is not implemented in this version of Frame Relay ? - if((chan->usedby == WANPIPE) && + if((chan->common.usedby == WANPIPE) && sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && @@ -1279,32 +1658,28 @@ printk(KERN_INFO "%s: WARNING: Unsupported IPX data in send, packet dropped\n", card->devname); - send_data = 0; } - } - - if (send_data) { - unsigned char attr = 0; - - /* For an API transmission, get rid of the API header */ - if (chan->usedby == API) { - api_tx_hdr_t* api_tx_hdr; - api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; - attr = api_tx_hdr->attr; - data += sizeof(api_tx_hdr_t); - len -= sizeof(api_tx_hdr_t); - } - - err = fr_send(card, chan->dlci, attr, len, data); + + }else{ + err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); if (err) { switch(err) { case FRRES_CIR_OVERFLOW: case FRRES_BUFFER_OVERFLOW: - setup_for_delayed_transmit(dev, data, - len); + if (!setup_for_delayed_transmit(dev, skb)){ + set_bit(1,&delay_tx_queued); + } chan->drvstats_if_send. if_send_adptr_bfrs_full ++; - break; + break; + + case FRRES_TOO_LONG: + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Error: Frame too long, transmission failed %i\n", + card->devname, (unsigned int)skb->len); + } + /* Drop down to default */ default: chan->drvstats_if_send. if_send_dlci_disconnected ++; @@ -1317,20 +1692,38 @@ if_send_bfr_passed_to_adptr++; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += len; - card->wandev.stats.tx_bytes += len; + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += skb->len; + card->wandev.stats.tx_bytes += skb->len; + #endif + + #ifdef LINUX_2_4 + dev->trans_start = jiffies; + #endif } } } - if (!netif_queue_stopped(dev)) - dev_kfree_skb(skb); +if_send_start_and_exit: + + start_net_queue(dev); + + /* If we queued the packet for transmission, we must not + * deallocate it. The packet is unlinked from the IP stack + * not copied. Therefore, we must keep the original packet */ + if (!test_bit(1,&delay_tx_queued)) { + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + adptr_flags->imask |= FR_INTR_TXRDY; + card->u.f.tx_interrupts_pending ++; + } - clear_bit(0, (void*)&card->wandev.critical); + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); s508_s514_unlock(card,&smp_flags); - return (netif_queue_stopped(dev)); + return 0; } @@ -1339,33 +1732,49 @@ * Setup so that a frame can be transmitted on the occurence of a transmit * interrupt. */ -static void setup_for_delayed_transmit (struct net_device* dev, void* buf, - unsigned len) +static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - fr508_flags_t* adptr_flags = card->flags; - fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + fr_dlci_interface_t* dlci_interface; + int len = skb->len; + + /* Check that the dlci is properly configured, + * before using tx interrupt */ + if (!chan->dlci_int_interface){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: ERROR on DLCI %i: Not configured properly !\n", + card->devname, chan->dlci); + printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", + card->devname); + } + return 1; + } + + dlci_interface = chan->dlci_int_interface; if(chan->transmit_length) { printk(KERN_INFO "%s: Big mess in setup_for_del...\n", card->devname); - return; + return 1; } if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { //FIXME: increment some statistic */ - return; + return 1; } + skb_unlink(skb); + chan->transmit_length = len; - memcpy(chan->transmit_buffer, buf, len); - + chan->delay_skb = skb; + dlci_interface->gen_interrupt |= FR_INTR_TXRDY; dlci_interface->packet_length = len; - adptr_flags->imask |= FR_INTR_TXRDY; - card->u.f.tx_interrupts_pending ++; + /* Turn on TX interrupt at the end of if_send */ + return 0; } @@ -1375,18 +1784,21 @@ * Return 0 if not broadcast/multicast address, otherwise return 1. */ -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb) { u32 src_ip_addr; u32 broadcast_ip_addr = 0; + #if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; + #endif fr_channel_t* chan = dev->priv; /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 14); /* read the IP broadcast address for the device */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; @@ -1395,13 +1807,15 @@ else return 0; } + #else + broadcast_ip_addr = dev->pa_brdaddr; + #endif /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++ chan->ifstats.tx_dropped; return 1; } @@ -1411,8 +1825,6 @@ printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++ chan->ifstats.tx_dropped; return 1; } @@ -1433,7 +1845,7 @@ fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; /* Set length of packet */ - len = sizeof(fr_encap_hdr_t)+ + len = //sizeof(fr_encap_hdr_t)+ sizeof(ip_pkt_t)+ sizeof(udp_pkt_t)+ sizeof(wp_mgmt_t)+ @@ -1481,7 +1893,7 @@ fr_udp_pkt->udp_pkt.udp_checksum = 0; fr_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)], + calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], udp_length+UDP_OFFSET); /* fill in IP length */ @@ -1499,7 +1911,7 @@ /* fill in IP checksum */ fr_udp_pkt->ip_pkt.hdr_checksum = 0; fr_udp_pkt->ip_pkt.hdr_checksum = - calc_checksum(&data[sizeof(fr_encap_hdr_t)], + calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], sizeof(ip_pkt_t)); return len; @@ -1588,9 +2000,13 @@ /*============================================================================ * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Return a pointer to struct enet_statistics. */ -static struct net_device_stats* if_stats (struct net_device* dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats *if_stats(netdevice_t *dev) +#else +static struct enet_statistics* if_stats (netdevice_t* dev) +#endif { fr_channel_t* chan = dev->priv; @@ -1603,7 +2019,12 @@ /****** Interrupt Handlers **************************************************/ /*============================================================================ - * S508 frame relay interrupt service routine. + * fr_isr: S508 frame relay interrupt service routine. + * + * Description: + * Frame relay main interrupt service route. This + * function check the interrupt type and takes + * the appropriate action. */ static void fr_isr (sdla_t* card) { @@ -1613,26 +2034,25 @@ fr_mbox_t* mbox = card->mbox; /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. - */ + * in sdlamain.c. */ card->in_isr = 1; ++card->statistics.isr_entry; - if(test_bit(1, (void*)&card->wandev.critical)) { - card->wandev.critical = 0; - flags->iflag = 0; - card->in_isr = 0; - return; - } + /* All peripheral (configuraiton, re-configuration) events + * take presidence over the ISR. Thus, retrigger */ + if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + ++card->statistics.isr_already_critical; + goto fr_isr_exit; + } + if(card->hw.type != SDLA_S514) { - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n", - card->devname, card->wandev.critical); + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", + card->devname); ++card->statistics.isr_already_critical; - card->in_isr = 0; - return; + goto fr_isr_exit; } } @@ -1649,12 +2069,12 @@ tx_intr(card); break; - case FR_INTR_READY: + case FR_INTR_READY: Intr_test_counter++; ++card->statistics.isr_intr_test; break; - case FR_INTR_DLC: /* Event interrupt occurred */ + case FR_INTR_DLC: /* Event interrupt occured */ mbox->cmd.command = FR_READ_STATUS; mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1680,27 +2100,31 @@ break; } +fr_isr_exit: + card->in_isr = 0; flags->iflag = 0; - if(card->hw.type != SDLA_S514) - clear_bit(0, (void*)&card->wandev.critical); + return; } -/*============================================================================ - * Receive interrupt handler. - * When a receive interrupt occurs do the following: - * 1- Find the structure for the dlci that the interrupt occurred on - * 2- If it doesn't exist then print appropriate msg and goto step 8. - * 3- If it exist then copy data to a skb. - * 4- If skb contains Sangoma UDP data then process them - * 5- If skb contains IPXWAN data then send IPXWAN reply packets - * 6- If skb contains Inverse Arp data then send Inv Arp replies - * 7- If skb contains any other data then decapsulate the packet and - * send it to the stack. - * 8- Release the receive element and update receive pointers on the board +/*=========================================================== + * rx_intr Receive interrupt handler. + * + * Description + * Upon receiveing an interrupt: + * 1. Check that the firmware is in sync with + * the driver. + * 2. Find an appropriate network interface + * based on the received dlci number. + * 3. Check that the netowrk interface exists + * and that it's setup properly. + * 4. Copy the data into an skb buffer. + * 5. Check the packet type and take + * appropriate acton: UPD, API, ARP or Data. */ + static void rx_intr (sdla_t* card) { fr_rx_buf_ctl_t* frbuf = card->rxmb; @@ -1708,11 +2132,13 @@ fr_channel_t* chan; char *ptr = &flags->iflag; struct sk_buff* skb; - struct net_device* dev; + netdevice_t* dev; void* buf; unsigned dlci, len, offs, len_incl_hdr; int i, udp_type; + + /* Check that firmware buffers are in sync */ if (frbuf->flag != 0x01) { printk(KERN_INFO @@ -1725,6 +2151,16 @@ printk(KERN_INFO "\n"); ++card->statistics.rx_intr_corrupt_rx_bfr; + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it means that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + fr_set_intr_mode(card, 0, 0, 0); return; } @@ -1732,134 +2168,206 @@ dlci = frbuf->dlci; offs = frbuf->offset; - /* Find network interface for this packet */ + /* Find the network interface for this packet */ dev = find_channel(card, dlci); - - if (dev == NULL) { + - /* unconfigured DLCI, so discard packet */ - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", + /* Check that the network interface is active and + * properly setup */ + if (dev == NULL) { + if( net_ratelimit()) { + printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", card->devname, dlci); + } ++card->statistics.rx_intr_on_orphaned_DLCI; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } - } else { - chan = dev->priv; + if ((chan = dev->priv) == NULL){ + if( net_ratelimit()) { + printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", + card->devname, dlci); + } + ++card->statistics.rx_intr_on_orphaned_DLCI; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } - skb = dev_alloc_skb(len); + skb = dev_alloc_skb(len); - if (!netif_running(dev) || (skb == NULL)) { - ++chan->ifstats.rx_dropped; - - if(netif_running(dev)) { + if (!is_dev_running(dev) || (skb == NULL)){ + ++chan->ifstats.rx_dropped; + + if(skb == NULL) { + if (net_ratelimit()) { printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - chan->drvstats_rx_intr.rx_intr_no_socket ++; - - } else - chan->drvstats_rx_intr. - rx_intr_dev_not_started ++; - } else { - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; - - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - - udp_type = udp_pkt_type( skb, card ); - - if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, - UDP_PKT_FRM_NETWORK, card, skb, dlci)) { - flags->imask |= FR_INTR_TIMER; - if (udp_type == UDP_FPIPE_TYPE){ - chan->drvstats_rx_intr. - rx_intr_PIPE_request ++; - } - } + "%s: no socket buffers available!\n", + card->devname); } + chan->drvstats_rx_intr.rx_intr_no_socket ++; + } - else if (chan->usedby == API) { - api_rx_hdr_t* api_rx_hdr; - chan->drvstats_rx_intr. - rx_intr_bfr_passed_to_stack ++; - chan->ifstats.rx_packets ++; - card->wandev.stats.rx_packets ++; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->attr = frbuf->attr; - api_rx_hdr->time_stamp = frbuf->tmstamp; - skb->protocol = htons(0x16); - skb->pkt_type = PACKET_HOST; - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - - } else if (handle_IPXWAN(skb->data,chan->name, - chan->enable_IPX, chan->network_number)) { - if (chan->enable_IPX) { - fr_send(card, dlci, 0, skb->len, - skb->data); - } - dev_kfree_skb(skb); + if (!is_dev_running(dev)){ + chan->drvstats_rx_intr. + rx_intr_dev_not_started ++; + if (skb){ + wan_dev_kfree_skb(skb, FREE_READ); + } + } + goto rx_done; + } -/*FIXME: Fix the ARPS in next release + /* Copy data from the board into the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) { + unsigned tmp = card->u.f.rx_top - offs + 1; - } else if (is_arp(skb->data)) { - if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { - printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname); - } - dev_kfree_skb(skb); -*/ + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } - } else if ( skb->data[0] != 0x03) { - printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname); - dev_kfree_skb(skb); + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); - } else { - len_incl_hdr = skb->len; - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; + /* We got the packet from the bard. + * Check the packet type and take appropriate action */ - /* remove hardware header */ - buf = skb_pull(skb, 1); + udp_type = udp_pkt_type( skb, card ); - if (!wanrouter_type_trans(skb, dev)) { - - /* can't decapsulate packet */ - dev_kfree_skb(skb); - chan->drvstats_rx_intr. - rx_intr_bfr_not_passed_to_stack ++; - ++ chan->ifstats.rx_errors; - ++ card->wandev.stats.rx_errors; - - } else { - netif_rx(skb); - chan->drvstats_rx_intr. - rx_intr_bfr_passed_to_stack ++; - ++ chan->ifstats.rx_packets; - ++ card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += len_incl_hdr; - card->wandev.stats.rx_bytes += - len_incl_hdr; + if(udp_type != UDP_INVALID_TYPE) { + + /* UDP Debug packet received, store the + * packet and handle it in timer interrupt */ + + skb_pull(skb, 1); + if (wanrouter_type_trans(skb, dev)){ + if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ + + flags->imask |= FR_INTR_TIMER; + + if (udp_type == UDP_FPIPE_TYPE){ + ++chan->drvstats_rx_intr.rx_intr_PIPE_request; } - } - } - } + } + } + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + }else if (chan->common.usedby == API) { + + /* We are in API mode. + * Add an API header to the RAW packet + * and queue it into a circular buffer. + * Then kick the fr_bh() bottom half handler */ + + api_rx_hdr_t* api_rx_hdr; + chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; + chan->ifstats.rx_packets ++; + card->wandev.stats.rx_packets ++; + + chan->ifstats.rx_bytes += skb->len; + card->wandev.stats.rx_bytes += skb->len; + + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->attr = frbuf->attr; + api_rx_hdr->time_stamp = frbuf->tmstamp; + + skb->protocol = htons(ETH_P_IP); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + bh_enqueue(dev, skb); + + trigger_fr_bh(chan); + #endif + + }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ + + //FIXME: Frame Relay IPX is not supported, Yet ! + //if (chan->enable_IPX) { + // fr_send(card, dlci, 0, skb->len,skb->data); + //} + wan_dev_kfree_skb(skb, FREE_READ); + + } else if (is_arp(skb->data)) { + + /* ARP support enabled Mar 16 2000 + * Process incoming ARP reply/request, setup + * dynamic routes. */ + + if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { + if (net_ratelimit()){ + printk (KERN_INFO + "%s: Error processing ARP Packet.\n", + card->devname); + } + } + wan_dev_kfree_skb(skb, FREE_READ); + + } else if (skb->data[0] != 0x03) { + + if (net_ratelimit()) { + printk(KERN_INFO "%s: Non IETF packet discarded.\n", + card->devname); + } + wan_dev_kfree_skb(skb, FREE_READ); + + } else { + + len_incl_hdr = skb->len; + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ + + /* Make sure it's an Ethernet frame, otherwise drop it */ + if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { + skb_pull(skb, 8); + skb->protocol=eth_type_trans(skb,dev); + }else{ + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + goto rx_done; + } + }else{ + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wanrouter_type_trans(skb, dev)) { + + /* can't decapsulate packet */ + wan_dev_kfree_skb(skb, FREE_READ); + + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + goto rx_done; + } + skb->mac.raw = skb->data; + } + + + /* Send a packed up the IP stack */ + netif_rx(skb); + ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.rx_bytes += len_incl_hdr; + card->wandev.stats.rx_bytes += len_incl_hdr; + #endif + } + +rx_done: /* Release buffer element and calculate a pointer to the next one */ frbuf->flag = 0; @@ -1869,14 +2377,36 @@ } -/*============================================================================ - * Transmit interrupt handler. +/*================================================================== + * tx_intr: Transmit interrupt handler. + * + * Rationale: + * If the board is busy transmitting, if_send() will + * buffers a single packet and turn on + * the tx interrupt. Tx interrupt will be called + * by the board, once the firmware can send more + * data. Thus, no polling is required. + * + * Description: + * Tx interrupt is called for each + * configured dlci channel. Thus: + * 1. Obtain the netowrk interface based on the + * dlci number. + * 2. Check that network interface is up and + * properly setup. + * 3. Check for a buffered packed. + * 4. Transmit the packed. + * 5. If we are in WANPIPE mode, mark the + * NET_BH handler. + * 6. If we are in API mode, kick + * the AF_WANPIPE socket for more data. + * */ static void tx_intr(sdla_t *card) { fr508_flags_t* flags = card->flags; fr_tx_buf_ctl_t* bctl; - struct net_device* dev = card->wandev.dev; + netdevice_t* dev; fr_channel_t* chan; if(card->hw.type == SDLA_S514){ @@ -1888,61 +2418,112 @@ /* Find the structure and make it unbusy */ dev = find_channel(card, flags->dlci); - chan = dev->priv; + if (dev == NULL){ + printk(KERN_INFO "NO DEV IN TX Interrupt\n"); + goto end_of_tx_intr; + } + + if ((chan = dev->priv) == NULL){ + printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); + goto end_of_tx_intr; + } - if(!chan->transmit_length) { + if(!chan->transmit_length || !chan->delay_skb) { printk(KERN_INFO "%s: tx int error - transmit length zero\n", card->wandev.name); - return; + goto end_of_tx_intr; } /* If the 'if_send()' procedure is currently checking the 'tbusy' status, then we cannot transmit. Instead, we configure the microcode so as to re-issue this transmit interrupt at a later stage. */ - if (test_bit(2, (void*)&card->wandev.critical)) { + if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; bctl->flag = 0xA0; dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - printk(KERN_INFO "%s: TX Interrupt Detected busy if_send\n",card->devname); + return; - } else { + }else{ bctl->dlci = flags->dlci; - bctl->length = chan->transmit_length; - sdla_poke(&card->hw, bctl->offset, chan->transmit_buffer, - chan->transmit_length); + bctl->length = chan->transmit_length+chan->fr_header_len; + sdla_poke(&card->hw, + fr_send_hdr(card,bctl->dlci,bctl->offset), + chan->delay_skb->data, + chan->delay_skb->len); bctl->flag = 0xC0; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) chan->ifstats.tx_bytes += chan->transmit_length; card->wandev.stats.tx_bytes += chan->transmit_length; - chan->transmit_length = 0; + #endif - /* if any other interfaces have transmit interrupts pending, */ - /* do not disable the global transmit interrupt */ - if(!(-- card->u.f.tx_interrupts_pending)) - flags->imask &= ~FR_INTR_TXRDY; + /* We must free an sk buffer, which we used + * for delayed transmission; Otherwise, the sock + * will run out of memory */ + wan_dev_kfree_skb(chan->delay_skb, FREE_WRITE); - netif_wake_queue (dev); + chan->delay_skb = NULL; + chan->transmit_length = 0; + + #ifdef LINUX_2_4 + dev->trans_start = jiffies; + #endif + + #ifdef LINUX_2_0 + wake_net_dev(dev); + #else + if (is_queue_stopped(dev)){ + /* If using API, than wakeup socket BH handler */ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + #endif } + +end_of_tx_intr: + + /* if any other interfaces have transmit interrupts pending, + * do not disable the global transmit interrupt */ + if(!(-- card->u.f.tx_interrupts_pending)) + flags->imask &= ~FR_INTR_TXRDY; + + } /*============================================================================ - * Timer interrupt handler. - FIXME: update comments as we modify the code - * The timer interrupt is used for three purposes: - * 1) Processing udp calls from 'fpipemon'. - * 2) Processing update calls from /proc file system - * 2) Reading board-level statistics for updating the proc file system. - * 3) Sending inverse ARP request packets. + * timer_intr: Timer interrupt handler. + * + * Rationale: + * All commans must be executed within the timer + * interrupt since no two commands should execute + * at the same time. + * + * Description: + * The timer interrupt is used to: + * 1. Processing udp calls from 'fpipemon'. + * 2. Processing update calls from /proc file system + * 3. Reading board-level statistics for + * updating the proc file system. + * 4. Sending inverse ARP request packets. + * 5. Configure a dlci/channel. + * 6. Unconfigure a dlci/channel. (Node only) */ + static void timer_intr(sdla_t *card) { fr508_flags_t* flags = card->flags; - if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { + /* UDP Debuging: fpipemon call */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { if(card->u.f.udp_type == UDP_FPIPE_TYPE) { if(process_udp_mgmt_pkt(card)) { card->u.f.timer_int_enabled &= @@ -1951,81 +2532,132 @@ } } - if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + /* /proc update call : triggered from update() */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { fr_get_err_stats(card); fr_get_stats(card); card->u.f.update_comms_stats = 0; card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; } + /* Update the channel state call. This is call is + * triggered by if_send() function */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ + netdevice_t *dev; + if (card->wandev.state == WAN_CONNECTED){ + for (dev=card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)){ + fr_channel_t *chan = dev->priv; + if (chan->common.state != WAN_CONNECTED){ + update_chan_state(dev); + } + } + } + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; + } -//FIXME: Fix the dynamic IP addressing -/* -goto L4; + /* configure a dlci/channel */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ + config_fr(card); + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } - // Used to send inarp request at given interval - if (card->wandev.state == WAN_CONNECTED) { - int num_remaining = 0; - - dev = card->wandev.dev; - while (dev) { - fr_channel_t *chan = dev->priv; - - if (chan->inarp == INARP_REQUEST && - chan->state == WAN_CONNECTED) { - num_remaining++; - - if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) { - send_inarp_request(card,dev); - chan->inarp_tick = jiffies; - } + /* unconfigure a dlci/channel */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ + unconfig_fr(card); + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; + } + + + /* Transmit ARP packets */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ + int i=0; + netdevice_t *dev; + + if (card->u.f.arp_dev == NULL) + card->u.f.arp_dev = card->wandev.dev; + + dev = card->u.f.arp_dev; + + for (;;){ + + fr_channel_t *chan = dev->priv; + + /* If the interface is brought down cancel sending In-ARPs */ + if (!(dev->flags&IFF_UP)){ + clear_bit(0,&chan->inarp_ready); + } + + if (test_bit(0,&chan->inarp_ready)){ + + if (check_tx_status(card,dev)){ + set_bit(ARP_CRIT,&card->wandev.critical); + break; + } + + if (!send_inarp_request(card,dev)){ + trigger_fr_arp(dev); + chan->inarp_tick = jiffies; + } + + clear_bit(0,&chan->inarp_ready); + dev = move_dev_to_next(card,dev); + break; + } + dev = move_dev_to_next(card,dev); + + if (++i == card->wandev.new_if_cnt){ + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; + break; } - dev = chan->slave; - } - if (!num_remaining) { // no more to process - flags->imask &= ~FR_INTR_TIMER; } + card->u.f.arp_dev = dev; } -L4: - ; -*/ + if(!card->u.f.timer_int_enabled) flags->imask &= ~FR_INTR_TIMER; } /*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o + * spur_intr: Spurious interrupt handler. + * + * Description: + * We don't know this interrupt. + * Print a warning. */ + static void spur_intr (sdla_t* card) { - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); + if (net_ratelimit()){ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); + } } + //FIXME: Fix the IPX in next version /*=========================================================================== * Return 0 for non-IPXWAN packet * 1 for IPXWAN packet or IPX is not enabled! * FIXME: Use a IPX structure here not offsets */ -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) +static int handle_IPXWAN(unsigned char *sendpacket, + char *devname, unsigned char enable_IPX, + unsigned long network_number) { int i; - if( sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) { + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { /* It's an IPX packet */ - if(!enable_IPX) { + if (!enable_IPX){ /* Return 1 so we don't pass it up the stack. */ //FIXME: Take this out when IPX is fixed - printk (KERN_INFO + if (net_ratelimit()){ + printk (KERN_INFO "%s: WARNING: Unsupported IPX packet received and dropped\n", devname); + } return 1; } } else { @@ -2033,39 +2665,33 @@ return 0; } - if( sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) - { + if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ /* It's IPXWAN */ - if( sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) - { + if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ + /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", + devname); /* Go through the routing options and answer no to every * option except Unnumbered RIP/SAP */ - for(i = 49; sendpacket[i] == 0x00; i += 5) - { + for(i = 49; sendpacket[i] == 0x00; i += 5){ /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02) - { + if( sendpacket[i + 4] != 0x02){ sendpacket[i + 1] = 0; } } /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ) - { + if( sendpacket[i] == 0x04 ){ i += 8; } /* We also want to turn off all header compression opt. */ - for(; sendpacket[i] == 0x80 ;) - { + for(; sendpacket[i] == 0x80 ;){ sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } @@ -2073,12 +2699,15 @@ /* Set the packet type to timer response */ sendpacket[42] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[42] == 0x02 ) - { + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", + devname); + + } else if( sendpacket[42] == 0x02 ){ + /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + printk(KERN_INFO + "%s: Received IPXWAN Information Request packet\n", + devname); /* Set the packet type to information response */ sendpacket[42] = 0x03; @@ -2103,10 +2732,10 @@ sendpacket[i] = 0; } - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", + devname); + } else { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } @@ -2128,86 +2757,166 @@ return 0; } /*============================================================================ - * Process Route. - * This routine is called as a polling routine to dynamically add/delete routes - * negotiated by inverse ARP. It is in this "task" because we don't want routes - * to be added while in interrupt context. -*/ + * process_route + * + * Rationale: + * If the interface goes down, or we receive an ARP request, + * we have to change the network interface ip addresses. + * This cannot be done within the interrupt. + * + * Description: + * + * This routine is called as a polling routine to dynamically + * add/delete routes negotiated by inverse ARP. It is in this + * "task" because we don't want routes to be added while in + * interrupt context. + * + * Usage: + * This function is called by fr_poll() polling funtion. + */ -static void process_route (sdla_t* card) +static void process_route (netdevice_t *dev) { - struct net_device* dev; - struct in_device *in_dev; - struct rtentry route; - int err = 0; - mm_segment_t fs; + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; +#if defined(LINUX_2_1) || defined(LINUX_2_4) - /* Dynamic Route adding/removing */ - dev = card->wandev.dev; - while (dev) { - fr_channel_t *chan = dev->priv; - - if (chan->route_flag == ADD_ROUTE || - chan->route_flag == REMOVE_ROUTE ) { - fs = get_fs(); - - in_dev = dev->ip_ptr; - - if( in_dev != NULL && in_dev->ifa_list != NULL) { - memset(&route, 0, sizeof(route)); - route.rt_dev = dev->name; - route.rt_flags = 0; - - ((struct sockaddr_in *) &(route.rt_dst)) -> - sin_addr.s_addr=in_dev->ifa_list->ifa_address; - ((struct sockaddr_in *) &(route.rt_dst)) -> - sin_family = AF_INET; - ((struct sockaddr_in *) &(route.rt_genmask)) -> - sin_addr.s_addr = 0xFFFFFFFF; - ((struct sockaddr_in *) &(route.rt_genmask)) -> - sin_family = AF_INET; - - switch(chan->route_flag) { - - case ADD_ROUTE: - set_fs(get_ds()); /* get user space block */ - err = ip_rt_ioctl( SIOCADDRT, &route); - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); - printk(KERN_INFO "%s: Address: %s\n", - chan->name, - in_ntoa(in_dev->ifa_list->ifa_address) ); - } else { - chan->route_flag = ROUTE_ADDED; - } - break; + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + u32 ip_tmp; + int err; - case REMOVE_ROUTE: - set_fs(get_ds()); /* get user space block */ - err = ip_rt_ioctl( SIOCDELRT, &route); - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); - printk(KERN_INFO "%s: Address: %s\n", - dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); - } else { - printk(KERN_INFO "%s: Removed route.\n", - chan->name); - chan->route_flag = NO_ROUTE; - } - break; - } /* Case Statement */ + + switch(chan->route_flag){ + + case ADD_ROUTE: + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = chan->ip_remote; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + if (err) { + + printk(KERN_INFO + "%s: Route Add failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + chan->name, in_ntoa(chan->ip_remote)); + + }else { + printk(KERN_INFO "%s: Route Added Successfully: %s\n", + card->devname,in_ntoa(chan->ip_remote)); + chan->route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = 0; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); + + if (err) { + + printk(KERN_INFO + "%s: Deleting of route failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(chan->ip_remote) ); + + } else { + + printk(KERN_INFO "%s: Route Removed Sucessfuly: %s\n", + card->devname,in_ntoa(ip_tmp)); + chan->route_flag = NO_ROUTE; + } + break; + + } /* Case Statement */ + +#else + /* Dynamic Route adding/removing */ + struct rtentry route; + int err = 0; + unsigned long fs = get_fs(); + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=dev->pa_dstaddr; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + switch(chan->route_flag) { + + case ADD_ROUTE: + + set_fs(get_ds()); /* get user space block */ + err = ip_rt_new(&route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + chan->name, in_ntoa(dev->pa_dstaddr) ); } - } /* If ADD/DELETE ROUTE */ + else { + chan->route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + + set_fs(get_ds()); /* get user space block */ + err = ip_rt_kill(&route); + set_fs(fs); /* restore old block */ - dev = chan->slave; - } /* Device 'While' Loop */ + if (err) { + + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(dev->pa_dstaddr) ); + } else { + + printk(KERN_INFO "%s: Removed route.\n", + ((fr_channel_t*)dev->priv)->name); + chan->route_flag = NO_ROUTE; + + } + break; + } + +#endif - card->poll = NULL; } @@ -2264,6 +2973,12 @@ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && fr_event(card, err, mbox)); + + /*NC Oct 12 2000 */ + if (err != CMD_OK){ + printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", + card->devname,err); + } return err; } @@ -2338,32 +3053,38 @@ } /*============================================================================ - * Disable communications. + * fr_comm_disable + * + * Warning: This functin is called by the shutdown() procedure. It is void + * since dev->priv are has already been deallocated and no + * error checking is possible using fr_event() function. */ -static int fr_comm_disable (sdla_t* card) +static void fr_comm_disable (sdla_t* card) { fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { + mbox->cmd.command = FR_SET_MODEM_STATUS; + mbox->cmd.length = 1; + mbox->data[0] = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry--); + + retry = MAX_CMD_RETRY; + do { mbox->cmd.command = FR_COMM_DISABLE; mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); + } while (err && retry--); + + return; +} - retry = MAX_CMD_RETRY; - do { - mbox->cmd.command = FR_SET_MODEM_STATUS; - mbox->cmd.length = 1; - mbox->data[0] = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} /*============================================================================ * Get communications error statistics. @@ -2518,9 +3239,58 @@ return err; } + +static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) +{ + netdevice_t *dev = find_channel(card,dlci); + fr_channel_t *chan; + + if (!dev || !(chan=dev->priv)) + return offset; + + if (chan->fr_header_len){ + sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); + } + + return offset+chan->fr_header_len; +} + /*============================================================================ * Send a frame on a selected DLCI. */ +static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, + void *buf, unsigned char hdr_len) +{ + fr_mbox_t* mbox = card->mbox + 0x800; + int retry = MAX_CMD_RETRY; + int err; + + do + { + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len+hdr_len; + mbox->cmd.command = FR_WRITE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + fr_tx_buf_ctl_t* frbuf; + + if(card->hw.type == SDLA_S514) + frbuf = (void*)(*(unsigned long*)mbox->data + + card->hw.dpmbase); + else + frbuf = (void*)(*(unsigned long*)mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); + + sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); + frbuf->flag = 0x01; + } + + return err; +} + static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, void *buf) { @@ -2538,7 +3308,6 @@ } while (err && retry-- && fr_event(card, err, mbox)); if (!err) { - fr_tx_buf_ctl_t* frbuf; if(card->hw.type == SDLA_S514) @@ -2555,6 +3324,7 @@ return err; } + /****** Firmware Asynchronous Event Handlers ********************************/ /*============================================================================ @@ -2577,46 +3347,41 @@ case FRRES_CHANNEL_DOWN: { - struct net_device *dev; + netdevice_t *dev; /* Remove all routes from associated DLCI's */ - dev = card->wandev.dev; - while (dev) { + for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) { fr_channel_t *chan = dev->priv; if (chan->route_flag == ROUTE_ADDED) { chan->route_flag = REMOVE_ROUTE; - card->poll = &process_route; } if (chan->inarp == INARP_CONFIGURED) { chan->inarp = INARP_REQUEST; } - dev = chan->slave; + /* If the link becomes disconnected then, + * all channels will be disconnected + * as well. + */ + set_chan_state(dev,WAN_DISCONNECTED); } - + wanpipe_set_state(card, WAN_DISCONNECTED); return 1; } case FRRES_CHANNEL_UP: { - struct net_device *dev; - int num_requests = 0; + netdevice_t *dev; - /* Remove all routes from associated DLCI's */ - dev = card->wandev.dev; - while (dev) { - fr_channel_t *chan = dev->priv; - if( chan->inarp == INARP_REQUEST ){ - num_requests++; - chan->inarp_tick = jiffies; - } - dev = chan->slave; + /* FIXME: Only startup devices that are on the list */ + + for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) { + + set_chan_state(dev,WAN_CONNECTED); } - /* Allow timer interrupts */ - if (num_requests) flags->imask |= 0x20; wanpipe_set_state(card, WAN_CONNECTED); return 1; } @@ -2644,8 +3409,10 @@ case FRRES_CIR_OVERFLOW: break; + case FRRES_BUFFER_OVERFLOW: break; + default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" , card->devname, mbox->cmd.command, event); @@ -2684,13 +3451,13 @@ dlci_status_t* status = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); fr_channel_t *chan; - struct net_device* dev2; + netdevice_t* dev2; for (; cnt; --cnt, ++status) { unsigned short dlci= status->dlci; - struct net_device* dev = find_channel(card, dlci); + netdevice_t* dev = find_channel(card, dlci); if (dev == NULL){ printk(KERN_INFO @@ -2707,7 +3474,7 @@ "%s: DLCI %u is inactive!\n", card->devname, dlci); - if (dev && netif_running(dev)) + if (dev && is_dev_running(dev)) set_chan_state(dev, WAN_DISCONNECTED); } @@ -2717,12 +3484,14 @@ "%s: DLCI %u has been deleted!\n", card->devname, dlci); - if (dev && netif_running(dev)) { + if (dev && is_dev_running(dev)){ + fr_channel_t *chan = dev->priv; if (chan->route_flag == ROUTE_ADDED) { chan->route_flag = REMOVE_ROUTE; - card->poll = &process_route; + /* The state change will trigger + * the fr polling routine */ } if (chan->inarp == INARP_CONFIGURED) { @@ -2740,16 +3509,15 @@ DLCI(s) when they become active. */ chan->dlci_configured = DLCI_CONFIG_PENDING; - - if (dev && netif_running(dev)) - set_chan_state(dev, WAN_CONNECTED); + + set_chan_state(dev, WAN_CONNECTED); } } } - dev2 = card->wandev.dev; - while (dev2) { + for (dev2 =card->wandev.dev; dev2; dev2 = *((netdevice_t **)dev2->priv)){ + chan = dev2->priv; if (chan->dlci_configured == DLCI_CONFIG_PENDING) { @@ -2758,7 +3526,6 @@ } } - dev2 = chan->slave; } return 1; } @@ -2767,8 +3534,7 @@ static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) { fr_dlc_conf_t cfg; - fr508_flags_t* flags = card->flags; - + memset(&cfg, 0, sizeof(cfg)); if ( chan->cir_status == CIR_DISABLED) { @@ -2786,22 +3552,16 @@ } if (fr_dlci_configure( card, &cfg , chan->dlci)){ - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); return 1; } chan->dlci_configured = DLCI_CONFIGURED; - /* Allow timer interrupts */ - if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) { - chan->inarp_tick = jiffies; - flags->imask |= 0x20; - } - /* Read the interface byte mapping into the channel - structure. + * structure. */ read_DLCI_IB_mapping( card, chan ); @@ -2812,7 +3572,7 @@ /*============================================================================ * Update channel state. */ -static int update_chan_state (struct net_device* dev) +static int update_chan_state (netdevice_t* dev) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -2828,14 +3588,25 @@ } while (err && retry-- && fr_event(card, err, mbox)); if (!err) { - + unsigned short* list = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(short); - + + err=1; + for (; cnt; --cnt, ++list) { if (*list == chan->dlci) { set_chan_state(dev, WAN_CONNECTED); + + + /* May 23 2000. NC + * When a dlci is added or restarted, + * the dlci_int_interface pointer must + * be reinitialized. */ + if (!chan->dlci_int_interface){ + err=fr_init_dlci (card,chan); + } break; } } @@ -2847,16 +3618,12 @@ /*============================================================================ * Set channel state. */ -static void set_chan_state (struct net_device* dev, int state) +static void set_chan_state (netdevice_t* dev, int state) { fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - unsigned long flags; - - save_flags(flags); - cli(); - if (chan->state != state) { + if (chan->common.state != state) { switch (state) { @@ -2864,6 +3631,12 @@ printk(KERN_INFO "%s: Interface %s: DLCI %d connected\n", card->devname, dev->name, chan->dlci); + + /* If the interface was previoulsy down, + * bring it up, since the channel is active */ + + trigger_fr_poll (dev); + trigger_fr_arp (dev); break; case WAN_CONNECTING: @@ -2876,20 +3649,29 @@ printk (KERN_INFO "%s: Interface %s: DLCI %d disconnected!\n", card->devname, dev->name, chan->dlci); + + /* If the interface is up, bring it down, + * since the channel is now disconnected */ + trigger_fr_poll (dev); break; } - chan->state = state; + chan->common.state = state; } chan->state_tick = jiffies; - restore_flags(flags); } /*============================================================================ * Find network device by its channel number. + * + * We need this critical flag because we change + * the dlci_to_dev_map outside the interrupt. + * + * NOTE: del_if() functions updates this array, it uses + * the spin locks to avoid corruption. */ -static struct net_device* find_channel (sdla_t* card, unsigned dlci) +static netdevice_t* find_channel (sdla_t* card, unsigned dlci) { if(dlci > HIGHEST_VALID_DLCI) return NULL; @@ -2945,9 +3727,15 @@ struct sk_buff *skb, int dlci) { int udp_pkt_stored = 0; - - if(!card->u.f.udp_pkt_lgth &&(skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.f.udp_pkt_lgth = skb->len; + + netdevice_t *dev=find_channel(card,dlci); + fr_channel_t *chan; + + if (!dev || !(chan=dev->priv)) + return 1; + + if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ + card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; card->u.f.udp_type = udp_type; card->u.f.udp_pkt_src = udp_pkt_src; card->u.f.udp_dlci = dlci; @@ -2960,8 +3748,12 @@ dlci); } - dev_kfree_skb(skb); - + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + return(udp_pkt_stored); } @@ -2982,7 +3774,7 @@ int err; struct timeval tv; int udp_mgmt_req_valid = 1; - struct net_device* dev; + netdevice_t* dev; fr_channel_t* chan; fr_udp_pkt_t *fr_udp_pkt; unsigned short num_trc_els; @@ -2995,7 +3787,14 @@ /* Find network interface for this packet */ dev = find_channel(card, dlci); - chan = dev->priv; + if (!dev){ + card->u.f.udp_pkt_lgth = 0; + return 1; + } + if ((chan = dev->priv) == NULL){ + card->u.f.udp_pkt_lgth = 0; + return 1; + } /* If the UDP packet is from the network, we are going to have to transmit a response. Before doing so, we must check to see that @@ -3003,39 +3802,49 @@ that we are not already in a 'delayed transmit' state. */ if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if (test_bit(0, (void*)&card->wandev.critical) || - test_bit(2, (void*)&card->wandev.critical)) { - return 0; - } - if((netif_queue_stopped(dev)) || (card->u.f.tx_interrupts_pending)) { - return 0; + if (check_tx_status(card,dev)){ + card->u.f.udp_pkt_lgth = 0; + return 1; } } fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; - switch(fr_udp_pkt->cblock.command) { + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(fr_udp_pkt->cblock.command) { - case FPIPE_ENABLE_TRACING: - case FPIPE_DISABLE_TRACING: - case FPIPE_GET_TRACE_INFO: - case FR_SET_FT1_MODE: - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - chan->drvstats_gen. - UDP_PIPE_mgmt_direction_err ++; + case FR_READ_MODEM_STATUS: + case FR_READ_STATUS: + case FPIPE_ROUTER_UP_TIME: + case FR_READ_ERROR_STATS: + case FPIPE_DRIVER_STAT_GEN: + case FR_READ_STATISTICS: + case FR_READ_ADD_DLC_STATS: + case FR_READ_CONFIG: + case FR_READ_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: udp_mgmt_req_valid = 0; break; - } - - default: - break; - } + } + } if(!udp_mgmt_req_valid) { /* set length to 0 */ fr_udp_pkt->cblock.length = 0; /* set return code */ fr_udp_pkt->cblock.result = 0xCD; + + chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,fr_udp_pkt->cblock.command); + } + } else { switch(fr_udp_pkt->cblock.command) { @@ -3074,7 +3883,7 @@ /* Calculate the maximum trace data area in */ /* the UDP packet */ card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - - sizeof(fr_encap_hdr_t) - + //sizeof(fr_encap_hdr_t) - sizeof(ip_pkt_t) - sizeof(udp_pkt_t) - sizeof(wp_mgmt_t) - @@ -3204,7 +4013,7 @@ case FPIPE_FT1_READ_STATUS: sdla_peek(&card->hw, 0xF020, &fr_udp_pkt->data[0x00] , 2); - fr_udp_pkt->cblock.length = 2; + fr_udp_pkt->cblock.length = mbox->cmd.length = 2; fr_udp_pkt->cblock.result = 0; break; @@ -3220,44 +4029,32 @@ chan->router_start_time; *(unsigned long *)&fr_udp_pkt->data = chan->router_up_time; - mbox->cmd.length = 4; + mbox->cmd.length = fr_udp_pkt->cblock.length = 4; + fr_udp_pkt->cblock.result = 0; break; - - case FR_FT1_STATUS_CTRL: - if(fr_udp_pkt->data[0] == 1) { - if(rCount++ != 0 ){ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if(fr_udp_pkt->data[0] == 0) { - if( --rCount != 0) { - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - case FPIPE_DRIVER_STAT_IFSEND: memcpy(fr_udp_pkt->data, &chan->drvstats_if_send.if_send_entry, sizeof(if_send_stat_t)); - mbox->cmd.length = sizeof(if_send_stat_t); + mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); + fr_udp_pkt->cblock.result = 0; break; case FPIPE_DRIVER_STAT_INTR: + memcpy(fr_udp_pkt->data, &card->statistics.isr_entry, sizeof(global_stats_t)); + memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], &chan->drvstats_rx_intr.rx_intr_no_socket, sizeof(rx_intr_stat_t)); - mbox->cmd.length = sizeof(global_stats_t) + + + mbox->cmd.length = fr_udp_pkt->cblock.length = + sizeof(global_stats_t) + sizeof(rx_intr_stat_t); + fr_udp_pkt->cblock.result = 0; break; case FPIPE_DRIVER_STAT_GEN: @@ -3268,13 +4065,34 @@ memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], &card->statistics, sizeof(global_stats_t)); - fr_udp_pkt->cblock.result = 0; - fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ + mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ sizeof(rx_intr_stat_t); - mbox->cmd.length = fr_udp_pkt->cblock.length; + fr_udp_pkt->cblock.result = 0; break; - + + + case FR_FT1_STATUS_CTRL: + if(fr_udp_pkt->data[0] == 1) { + if(rCount++ != 0 ){ + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if(fr_udp_pkt->data[0] == 0) { + if( --rCount != 0) { + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + goto udp_mgmt_dflt; + + default: +udp_mgmt_dflt: do { memcpy(&mbox->cmd, &fr_udp_pkt->cblock.command, @@ -3312,12 +4130,19 @@ len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - err = fr_send(card, dlci, 0, len, card->u.f.udp_pkt_data); - if (err) + + chan->fr_header_len=2; + chan->fr_header[0]=Q922_UI; + chan->fr_header[1]=NLPID_IP; + + err = fr_send_data_header(card, dlci, 0, len, + card->u.f.udp_pkt_data,chan->fr_header_len); + if (err){ chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; - else + }else{ chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; + } + } else { /* Allocate socket buffer */ if((new_skb = dev_alloc_skb(len)) != NULL) { @@ -3326,22 +4151,12 @@ buf = skb_put(new_skb, len); memcpy(buf, card->u.f.udp_pkt_data, len); - /* Decapsulate packet and pass it up the protocol - stack */ + chan->drvstats_gen. + UDP_PIPE_mgmt_passed_to_stack ++; new_skb->dev = dev; - buf = skb_pull(new_skb, 1); /* remove hardware header*/ - - if(!wanrouter_type_trans(new_skb, dev)) { - - chan->drvstats_gen. - UDP_PIPE_mgmt_not_passed_to_stack ++; - /* can't decapsulate packet */ - dev_kfree_skb(new_skb); - } else { - chan->drvstats_gen. - UDP_PIPE_mgmt_passed_to_stack ++; - netif_rx(new_skb); - } + new_skb->protocol = htons(ETH_P_IP); + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); } else { chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; @@ -3360,15 +4175,19 @@ * Send Inverse ARP Request */ -int send_inarp_request(sdla_t *card, struct net_device *dev) +int send_inarp_request(sdla_t *card, netdevice_t *dev) { + int err=0; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + arphdr_1490_t *ArpPacket; arphdr_fr_t *arphdr; fr_channel_t *chan = dev->priv; struct in_device *in_dev; in_dev = dev->ip_ptr; - + if(in_dev != NULL ) { ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); @@ -3396,14 +4215,64 @@ arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ arphdr->ar_tip = 0; /* Remote Address -- what we want */ - printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); - fr_send(card, chan->dlci, 0, - sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), - (void *)ArpPacket); + err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + + if (!err){ + printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", + card->devname, chan->dlci); + clear_bit(ARP_CRIT,&card->wandev.critical); + } + kfree(ArpPacket); + }else{ + printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", + card->devname,dev->name); + return 1; } - return 1; +#else + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + + ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + arphdr->ar_sip = dev->pa_addr; /* Local Address */ + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); + err = fr_send(card, chan->dlci, 0, + sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + + if (!err){ + printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", + card->devname, chan->dlci); + clear_bit(ARP_CRIT,&card->wandev.critical); + } + + kfree(ArpPacket); +#endif + + return 0; } @@ -3426,151 +4295,312 @@ * Process ARP Packet Type */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev) { + +#if defined(LINUX_2_1) || defined(LINUX_2_4) arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ fr_rx_buf_ctl_t* frbuf = card->rxmb; struct in_device *in_dev; + fr_channel_t *chan = dev->priv; +#else + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + fr_rx_buf_ctl_t* frbuf = card->rxmb; +#endif + + /* Before we transmit ARP packet, we must check + * to see that we are not currently transmitting a + * frame (in 'if_send()') and that we are not + * already in a 'delayed transmit' state. */ + if (check_tx_status(card,dev)){ + if (net_ratelimit()){ + printk(KERN_INFO "%s: Disabling comminication to process ARP\n", + card->devname); + } + set_bit(ARP_CRIT,&card->wandev.critical); + return 0; + } +#if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; - if( in_dev != NULL && in_dev->ifa_list != NULL) { - switch (ntohs(arphdr->ar_op)) { - case 0x08: // Inverse ARP request -- Send Reply, add route. + /* Check that IP addresses exist for our network address */ + if (in_dev == NULL || in_dev->ifa_list == NULL) + return -1; + + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %s\n", + card->devname, in_ntoa(arphdr->ar_sip)); - if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); - printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask); - printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local); - return -1; - } - - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); - return -1; - } + + /* Check that the network address is the same as ours, only + * if the netowrk mask is not 255.255.255.255. Otherwise + * this check would not make sense */ + + if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && + (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != + (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ + + printk(KERN_INFO + "%s: Invalid PtP address. %s InARP ignored.\n", + card->devname,in_ntoa(arphdr->ar_sip)); + + printk(KERN_INFO "%s: mask %s\n", + card->devname, in_ntoa(in_dev->ifa_list->ifa_mask)); + printk(KERN_INFO "%s: local %s\n", + card->devname,in_ntoa(in_dev->ifa_list->ifa_local)); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ + printk(KERN_INFO + "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } - arphdr->ar_op = htons(0x09); /* InARP Reply */ + arphdr->ar_op = htons(0x09); /* InARP Reply */ - /* Set addresses */ - arphdr->ar_tip = arphdr->ar_sip; - arphdr->ar_sip = in_dev->ifa_list->ifa_local; + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; - fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; - /* Modify Point-to-Point Address */ - { - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - int err; - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = arphdr->ar_tip; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); - set_fs(fs); /* restore old block */ + if (test_bit(ARP_CRIT,&card->wandev.critical)){ + if (net_ratelimit()){ + printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", + card->devname); } - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ + } + clear_bit(ARP_CRIT,&card->wandev.critical); + + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; - ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; - card->poll = &process_route; + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ - break; + chan->route_flag = ADD_ROUTE; + trigger_fr_poll (dev); - case 0x09: // Inverse ARP reply + break; - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + case 0x09: // Inverse ARP reply - if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); - return -1; - } + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", + card->devname, in_ntoa(arphdr->ar_sip)); - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); - return -1; - } - /* Modify Point-to-Point Address */ - { - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - int err; + /* Compare network addresses, only if network mask + * is not 255.255.255.255 It would not make sense + * to perform this test if the mask was all 1's */ - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); + if (in_dev->ifa_list->ifa_mask != 0xffffffff && + (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != + (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = arphdr->ar_sip; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", + card->devname); + return -1; + } - set_fs(fs); /* restore old block */ - } + /* Make sure that the received IP address is not + * the same as our own local address */ + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; - ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; - ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; - card->poll = &process_route; - - break; - default: // ARP's and RARP's -- Shouldn't happen. - } + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + chan->route_flag = ADD_ROUTE; + chan->inarp = INARP_CONFIGURED; + trigger_fr_poll(dev); + + break; + default: // ARP's and RARP's -- Shouldn't happen. } return 0; -} - +#else -/*============================================================================== - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ - * TEST_COUNTER times. - */ -static int intr_test( sdla_t* card ) -{ - fr_mbox_t* mb = card->mbox; - int err,i; + switch (ntohs(arphdr->ar_op)) { - /* The critical flag is unset here because we want to get into the - ISR without the flag already set. The If_open sets the flag. - */ - clear_bit(1, (void*)&card->wandev.critical); + case 0x08: // Inverse ARP request -- Send Reply, add route. - err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); - - if (err == CMD_OK) { + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", + ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); - for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { - /* Run command READ_CODE_VERSION */ - mb->cmd.length = 0; - mb->cmd.command = FR_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - fr_event(card, err, mb); + + if (dev->pa_mask != 0xFFFFFFFF){ + + if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", + card->devname); + return -1; + } + } + + if (dev->pa_addr == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = dev->pa_addr; + + fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + + clear_bit(ARP_CRIT,&card->wandev.critical); + + /* Modify Point-to-Point Address */ + dev->pa_dstaddr = arphdr->ar_tip; + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + trigger_fr_poll(dev); + + break; + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", + ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", + card->devname); + return -1; + } + + if (dev->pa_addr == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + return -1; + } + + /* Modify Point-to-Point Address */ + dev->pa_dstaddr = arphdr->ar_sip; + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; + trigger_fr_poll(dev); + + break; + default: // ARP's and RARP's -- Shouldn't happen. + } + + return 0; + +#endif +} + + +/*============================================================ + * trigger_fr_arp + * + * Description: + * Add an fr_arp() task into a arp + * timer handler for a specific dlci/interface. + * This will kick the fr_arp() routine + * within the specified time interval. + * + * Usage: + * This timer is used to send ARP requests at + * certain time intervals. + * Called by an interrupt to request an action + * at a later date. + */ + +static void trigger_fr_arp (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + del_timer(&chan->fr_arp_timer); + chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ); + add_timer(&chan->fr_arp_timer); + return; +} + + + +/*============================================================================== + * ARP Request Action + * + * This funciton is called by timer interrupt to send an arp request + * to the remote end. + */ + +static void fr_arp (unsigned long data) +{ + netdevice_t *dev = (netdevice_t *)data; + fr_channel_t *chan = dev->priv; + volatile sdla_t *card = chan->card; + fr508_flags_t* flags = card->flags; + + /* Send ARP packets for all devs' until + * ARP state changes to CONFIGURED */ + + if (chan->inarp == INARP_REQUEST && + chan->common.state == WAN_CONNECTED && + card->wandev.state == WAN_CONNECTED){ + set_bit(0,&chan->inarp_ready); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; + flags->imask |= FR_INTR_TIMER; + } + + return; +} + + +/*============================================================================== + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ + * TEST_COUNTER times. + */ +static int intr_test( sdla_t* card ) +{ + fr_mbox_t* mb = card->mbox; + int err,i; + + err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); + + if (err == CMD_OK) { + + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { + /* Run command READ_CODE_VERSION */ + mb->cmd.length = 0; + mb->cmd.command = FR_READ_CODE_VERSION; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + fr_event(card, err, mb); } } else { @@ -3582,7 +4612,6 @@ if( err != CMD_OK ) return err; - set_bit(1, (void*)&card->wandev.critical); return 0; } @@ -3593,6 +4622,9 @@ { fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; + /* Quick HACK */ + + if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && (fr_udp_pkt->udp_pkt.udp_dst_port == @@ -3600,10 +4632,10 @@ (fr_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { if(!strncmp(fr_udp_pkt->wp_mgmt.signature, - UDPMGMT_FPIPE_SIGNATURE, 8)) + UDPMGMT_FPIPE_SIGNATURE, 8)){ return UDP_FPIPE_TYPE; + } } - return UDP_INVALID_TYPE; } @@ -3674,38 +4706,772 @@ card->devname, chan->dlci); } + + void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) { - if (card->hw.type != SDLA_S514){ -#ifdef CONFIG_SMP - spin_lock_irqsave(&card->lock, *smp_flags); -#else - disable_irq(card->hw.irq); -#endif + + #if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + #else + disable_irq(card->hw.irq); + #endif + }else{ + #if defined(__SMP__) || defined(LINUX_2_4) + spin_lock(&card->u.f.if_send_lock); + #endif } -#ifdef CONFIG_SMP - else{ - spin_lock(&card->lock); - } -#endif + return; } + void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) { if (card->hw.type != SDLA_S514){ -#ifdef CONFIG_SMP - spin_unlock_irqrestore(&card->lock, *smp_flags); -#else - enable_irq(card->hw.irq); -#endif + + #if defined(__SMP__) || defined(LINUX_2_4) + spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); + #else + enable_irq(card->hw.irq); + #endif + }else{ + #if defined(__SMP__) || defined(LINUX_2_4) + spin_unlock(&card->u.f.if_send_lock); + #endif } -#ifdef CONFIG_SMP - else{ - spin_unlock(&card->lock); + return; +} + + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + +/*---------------------------------------------------------------------- + RECEIVE INTERRUPT: BOTTOM HALF HANDLERS + ----------------------------------------------------------------------*/ + + +/*======================================================== + * bh_enqueue + * + * Description: + * Insert a received packed into a circular + * rx queue. This packed will be picked up + * by fr_bh() and sent up the stack to the + * user. + * + * Usage: + * This function is called by rx interrupt, + * in API mode. + * + */ + +static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb) +{ + /* Check for full */ + fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + + if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ + ++card->wandev.stats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + return 1; + } + + ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; + + if (chan->bh_write == (MAX_BH_BUFF-1)){ + chan->bh_write=0; + }else{ + ++chan->bh_write; + } + + atomic_inc(&chan->bh_buff_used); + + return 0; +} + + +/*======================================================== + * trigger_fr_bh + * + * Description: + * Kick the fr_bh() handler + * + * Usage: + * rx interrupt calls this function during + * the API mode. + */ + +static void trigger_fr_bh (fr_channel_t *chan) +{ + if (!test_and_set_bit(0,&chan->tq_working)){ + wanpipe_queue_tq(&chan->common.wanpipe_task); + wanpipe_mark_bh(); + } +} + + +/*======================================================== + * fr_bh + * + * Description: + * Frame relay receive BH handler. + * Dequeue data from the BH circular + * buffer and pass it up the API sock. + * + * Rationale: + * This fuction is used to offload the + * rx_interrupt during API operation mode. + * The fr_bh() function executes for each + * dlci/interface. + * + * Once receive interrupt copies data from the + * card into an skb buffer, the skb buffer + * is appended to a circular BH buffer. + * Then the interrupt kicks fr_bh() to finish the + * job at a later time (no within the interrupt). + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ + +static void fr_bh (netdevice_t * dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + struct sk_buff *skb; + + if (atomic_read(&chan->bh_buff_used) == 0){ + clear_bit(0, &chan->tq_working); + return; + } + + while (atomic_read(&chan->bh_buff_used)){ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + clear_bit(0, &chan->tq_working); + return; + } + + skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; + + if (skb != NULL){ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + ++card->wandev.stats.rx_dropped; + ++chan->ifstats.rx_dropped; + wan_dev_kfree_skb(skb, FREE_READ); + fr_bh_cleanup(dev); + continue; + } + + if (chan->common.func(skb,dev,chan->common.sk) != 0){ + /* Sock full cannot send, queue us for + * another try */ + atomic_set(&chan->common.receive_block,1); + return; + }else{ + fr_bh_cleanup(dev); + } + }else{ + fr_bh_cleanup(dev); + } } + clear_bit(0, &chan->tq_working); + + return; +} + +static int fr_bh_cleanup (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; + + if (chan->bh_read == (MAX_BH_BUFF-1)){ + chan->bh_read=0; + }else{ + ++chan->bh_read; + } + + atomic_dec(&chan->bh_buff_used); + return 0; +} #endif + +/*---------------------------------------------------------------------- + POLL BH HANDLERS AND KICK ROUTINES + ----------------------------------------------------------------------*/ + +/*============================================================ + * trigger_fr_poll + * + * Description: + * Add a fr_poll() task into a tq_scheduler bh handler + * for a specific dlci/interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ +static void trigger_fr_poll (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + #ifdef LINUX_2_4 + schedule_task(&chan->fr_poll_task); + #else + queue_task(&chan->fr_poll_task, &tq_scheduler); + #endif + return; } + + +/*============================================================ + * fr_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * Frame relay polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each frame relay + * dlci/interface through a tq_schedule bottom half. + * + * trigger_fr_poll() function is used to kick + * the fr_poll routine. + */ + +static void fr_poll (netdevice_t *dev) +{ + + fr_channel_t* chan; + sdla_t *card; + u8 check_gateway=0; + + if (!dev || (chan = dev->priv) == NULL) + return; + + card = chan->card; + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + switch (chan->common.state){ + + case WAN_DISCONNECTED: + + if (test_bit(DYN_OPT_ON,&chan->interface_down) && + !test_bit(DEV_DOWN, &chan->interface_down) && + dev->flags&IFF_UP){ + + printk(KERN_INFO "%s: Interface %s is Down.\n", + card->devname,dev->name); + change_dev_flags(dev,dev->flags&~IFF_UP); + set_bit(DEV_DOWN, &chan->interface_down); + chan->route_flag = NO_ROUTE; + + }else{ + if (chan->inarp != INARP_NONE) + process_route(dev); + } + break; + + case WAN_CONNECTED: + + if (test_bit(DYN_OPT_ON,&chan->interface_down) && + test_bit(DEV_DOWN, &chan->interface_down) && + !(dev->flags&IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s is Up.\n", + card->devname,dev->name); + + change_dev_flags(dev,dev->flags|IFF_UP); + clear_bit(DEV_DOWN, &chan->interface_down); + check_gateway=1; + } + + if (chan->inarp != INARP_NONE){ + process_route(dev); + check_gateway=1; + } + + if (chan->gateway && check_gateway) + add_gateway(card,dev); + + break; + + } + + return; +} + +/*============================================================== + * check_tx_status + * + * Rationale: + * We cannot transmit from an interrupt while + * the if_send is transmitting data. Therefore, + * we must check whether the tx buffers are + * begin used, before we transmit from an + * interrupt. + * + * Description: + * Checks whether it's safe to use the transmit + * buffers. + * + * Usage: + * ARP and UDP handling routines use this function + * because, they need to transmit data during + * an interrupt. + */ + +static int check_tx_status(sdla_t *card, netdevice_t *dev) +{ + + if (card->hw.type == SDLA_S514){ + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || + test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { + return 1; + } + } + + if (is_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) + return 1; + + return 0; +} + +/*=============================================================== + * move_dev_to_next + * + * Description: + * Move the dev pointer to the next location in the + * link list. Check if we are at the end of the + * list, if so start from the begining. + * + * Usage: + * Timer interrupt uses this function to efficiently + * step through the devices that need to send ARP data. + * + */ + +netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + if (card->wandev.new_if_cnt != 1){ + if (*((netdevice_t **)dev->priv) == NULL){ + return card->wandev.dev; + }else{ + return *((netdevice_t **)dev->priv); + } + } + return dev; +} + +/*============================================================== + * trigger_config_fr + * + * Rationale: + * All commands must be performed inside of a + * interrupt. + * + * Description: + * Kick the config_fr() routine throught the + * timer interrupt. + */ + + +static void trigger_config_fr (sdla_t *card) +{ + fr508_flags_t* flags = card->flags; + + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->imask |= FR_INTR_TIMER; +} + + +/*============================================================== + * config_fr + * + * Rationale: + * All commands must be performed inside of a + * interrupt. + & + * Description: + * Configure a DLCI. This function is executed + * by a timer_interrupt. The if_open() function + * triggers it. + * + * Usage: + * new_if() collects all data necessary to + * configure the DLCI. It sets the chan->dlci_ready + * bit. When the if_open() function is executed + * it checks this bit, and if its set it triggers + * the timer interrupt to execute the config_fr() + * function. + */ + +static void config_fr (sdla_t *card) +{ + netdevice_t *dev; + fr_channel_t *chan; + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){ + + if ((chan=dev->priv) == NULL) + continue; + + if (!test_bit(0,&chan->config_dlci)) + continue; + + clear_bit(0,&chan->config_dlci); + + /* If signalling is set to NO, then setup + * DLCI addresses right away. Don't have to wait for + * link to connect. + */ + if (card->wandev.signalling == WANOPT_NO){ + printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", + card->wandev.name); + if (fr_init_dlci(card,chan)){ + printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", + card->devname, chan->dlci); + return; + } + } + + if (card->wandev.station == WANOPT_CPE) { + + update_chan_state(dev); + + /* CPE: issue full status enquiry */ + fr_issue_isf(card, FR_ISF_FSE); + + } else { + /* FR switch: activate DLCI(s) */ + + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + + if (!check_dlci_config (card, chan)){ + fr_add_dlci(card, chan->dlci); + fr_activate_dlci(card, chan->dlci); + } + } + + card->u.f.dlci_to_dev_map[chan->dlci] = dev; + } + return; +} + + +/*============================================================== + * config_fr + * + * Rationale: + * All commands must be executed during an interrupt. + * + * Description: + * Trigger uncofig_fr() function through + * the timer interrupt. + * + */ + +static void trigger_unconfig_fr (netdevice_t *dev) +{ + fr_channel_t *chan = dev->priv; + volatile sdla_t *card = chan->card; + u32 timeout; + fr508_flags_t* flags = card->flags; + int reset_critical=0; + + if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ + clear_bit(PERI_CRIT,(void*)&card->wandev.critical); + reset_critical=1; + } + + /* run unconfig_dlci() function + * throught the timer interrupt */ + set_bit(0,(void*)&chan->unconfig_dlci); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; + flags->imask |= FR_INTR_TIMER; + + /* Wait for the command to complete */ + timeout = jiffies; + for(;;) { + + if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) + break; + + if ((jiffies - timeout) > (1 * HZ)){ + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; + printk(KERN_INFO "%s: Failed to delete DLCI %i\n", + card->devname,chan->dlci); + break; + } + } + + if (reset_critical){ + set_bit(PERI_CRIT,(void*)&card->wandev.critical); + } +} + +/*============================================================== + * unconfig_fr + * + * Rationale: + * All commands must be executed during an interrupt. + * + * Description: + * Remove the dlci from firmware. + * This funciton is used in NODE shutdown. + */ + +static void unconfig_fr (sdla_t *card) +{ + netdevice_t *dev; + fr_channel_t *chan; + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){ + + if ((chan=dev->priv) == NULL) + continue; + + if (!test_bit(0,&chan->unconfig_dlci)) + continue; + + clear_bit(0,&chan->unconfig_dlci); + + if (card->wandev.station == WANOPT_NODE){ + printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", + card->devname,chan->dlci); + fr_delete_dlci(card,chan->dlci); + } + card->u.f.dlci_to_dev_map[chan->dlci] = NULL; + } +} + +static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode) +{ + struct sk_buff *skb = *skb_orig; + fr_channel_t *chan=dev->priv; + + if (op_mode == WANPIPE){ + + chan->fr_header[0]=Q922_UI; + + switch (htons(skb->protocol)){ + + case ETH_P_IP: + chan->fr_header[1]=NLPID_IP; + break; + default: + return -EINVAL; + } + + return 2; + } + + /* If we are in bridging mode, we must apply + * an Ethernet header */ + if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){ + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + + /* Encapsulate the packet as a bridged Ethernet frame. */ + #ifdef DEBUG + printk(KERN_INFO "%s: encapsulating skb for frame relay\n", + dev->name); + #endif + + chan->fr_header[0] = 0x03; + chan->fr_header[1] = 0x00; + chan->fr_header[2] = 0x80; + chan->fr_header[3] = 0x00; + chan->fr_header[4] = 0x80; + chan->fr_header[5] = 0xC2; + chan->fr_header[6] = 0x00; + chan->fr_header[7] = 0x07; + + /* Yuck. */ + skb->protocol = ETH_P_802_3; + return 8; + + #else + + /* BRIDGING is not supported in 2.0.X */ + return -EINVAL; + + #endif + } + + return 0; +} + + +static int check_dlci_config (sdla_t *card, fr_channel_t *chan) +{ + fr_mbox_t* mbox = card->mbox; + int err=0; + fr_conf_t *conf=NULL; + unsigned short dlci_num = chan->dlci; + int dlci_offset=0; + netdevice_t *dev=NULL; + + mbox->cmd.command = FR_READ_CONFIG; + mbox->cmd.length = 0; + mbox->cmd.dlci = dlci_num; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err == CMD_OK){ + return 0; + } + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + set_chan_state(dev,WAN_DISCONNECTED); + } + + printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); + + mbox->cmd.command = FR_COMM_DISABLE; + mbox->cmd.length = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK){ + fr_event(card, err, mbox); + return 2; + } + + printk(KERN_INFO "Disabled Communications \n"); + + mbox->cmd.command = FR_READ_CONFIG; + mbox->cmd.length = 0; + mbox->cmd.dlci = 0; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK){ + fr_event(card, err, mbox); + return 2; + } + + conf = (fr_conf_t *)mbox->data; + + dlci_offset=0; + for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + fr_channel_t *chan_tmp = dev->priv; + conf->dlci[dlci_offset] = chan_tmp->dlci; + dlci_offset++; + } + + printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", + mbox->cmd.length, + mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, + dlci_offset ); + + mbox->cmd.length = 0x20 + dlci_offset*2; + + mbox->cmd.command = FR_SET_CONFIG; + mbox->cmd.dlci = 0; + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK){ + fr_event(card, err, mbox); + return 2; + } + + initialize_rx_tx_buffers (card); + + + printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); + + if (fr_comm_enable (card)){ + return 2; + } + + printk(KERN_INFO "Enabling Communications \n"); + + for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + fr_channel_t *chan_tmp = dev->priv; + fr_init_dlci(card,chan_tmp); + fr_add_dlci(card, chan_tmp->dlci); + fr_activate_dlci(card, chan_tmp->dlci); + } + + printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); + + return 1; +} + +static void initialize_rx_tx_buffers (sdla_t *card) +{ + fr_buf_info_t* buf_info; + + if (card->hw.type == SDLA_S514) { + + buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + + FR508_RXBC_OFFS); + + card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + + card->hw.dpmbase); + }else{ + buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); + + card->rxmb = (void*)(buf_info->rse_next - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - + FR_MB_VECTOR + card->hw.dpmbase); + } + + card->u.f.rx_base = buf_info->buf_base; + card->u.f.rx_top = buf_info->buf_top; + + card->u.f.tx_interrupts_pending = 0; + + return; +} + + + /****** End *****************************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_ft1.c linux/drivers/net/wan/sdla_ft1.c --- v2.4.3/linux/drivers/net/wan/sdla_ft1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/sdla_ft1.c Thu Apr 12 12:11:39 2001 @@ -0,0 +1,386 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Authors: Nenad Corbic <ncorbic@sangoma.com> +* Gideon Hack +* +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. +* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing +* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include <linux/version.h> +#include <linux/kernel.h> /* printk(), and other useful stuff */ +#include <linux/stddef.h> /* offsetof(), etc. */ +#include <linux/errno.h> /* return codes */ +#include <linux/string.h> /* inline memset(), etc. */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ +#include <linux/wanrouter.h> /* WAN router definitions */ +#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ +#include <linux/if_arp.h> /* ARPHRD_* defines */ + +#if defined(LINUX_2_4) + #include <linux/inetdevice.h> + #include <asm/uaccess.h> + +#elif defined(LINUX_2_1) + #include <linux/inetdevice.h> + #include <asm/uaccess.h> + +#else + #include <net/route.h> /* Adding new route entries */ + #include <asm/segment.h> + #define test_and_set_bit set_bit +#endif + +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> +#include <linux/if.h> +#include <asm/byteorder.h> /* htons(), etc. */ +#include <linux/sdlapci.h> +#include <asm/io.h> + +#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x0001 +#define TMR_INT_ENABLED_UPDATE 0x0002 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define WANPIPE 0x00 +#define API 0x01 +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + netdevice_t *slave; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + //FIXME: add driver stats as per frame relay! + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpft1_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + + union + { + char str[80]; + } u; + volatile CHDLC_MAILBOX_STRUCT* mb; + CHDLC_MAILBOX_STRUCT* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Use primary port */ + card->u.c.comm_port = 0; + + + /* Initialize protocol-specific fields */ + if(card->hw.type != SDLA_S514){ + card->mbox = (void *) card->hw.dpmbase; + }else{ + card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; + } + + mb = mb1 = card->mbox; + + if (!card->configured){ + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", + card->devname, u.str); + + card->isr = NULL; + card->poll = NULL; + card->exec = &wpft1_exec; + card->wandev.update = NULL; + card->wandev.new_if = NULL; + card->wandev.del_if = NULL; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* This is for the ports link state */ + card->u.c.state = WAN_DISCONNECTED; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = 0x7F; + card->wandev.interface = 0; + + card->wandev.clocking = 0; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + card->wandev.bps = 0; + + card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->buffer_length = 0; + mb1->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; + if(err != COMMAND_OK) { + chdlc_error(card, err, mb1); + return -EIO; + } + + if(card->hw.type == SDLA_S514){ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct)); + }else{ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + } + + card->wandev.state = WAN_FT1_READY; + printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); + + return 0; +} + +static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + int len; + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ + return -EFAULT; + } + + len = mbox->buffer_length; + + if (len) { + if( copy_from_user((void*)&mbox->data, u_data, len)){ + return -EFAULT; + } + } + + /* execute command */ + if (!sdla_exec(mbox)){ + return -EIO; + } + + /* return result */ + if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ + return -EFAULT; + } + + len = mbox->buffer_length; + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ + return -EFAULT; + } + +#else + + if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(ft1_exec_cmd_t))){ + return -EFAULT; + } + + memcpy_fromfs((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t)); + + len = mbox->buffer_length; + + if (len) { + if (!u_data || verify_area(VERIFY_READ, u_data, len)) + return -EFAULT; + memcpy_fromfs((void*)&mbox->data, u_data, len); + } + + /* execute command */ + if (!sdla_exec(mbox)) + return -EIO; + + /* return result */ + memcpy_tofs(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t)); + len = mbox->buffer_length; + + if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)){ + memcpy_tofs(u_data, (void*)&mbox->data, len); + } + +#endif + + return 0; + +} + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c --- v2.4.3/linux/drivers/net/wan/sdla_ppp.c Tue Mar 6 19:44:36 2001 +++ linux/drivers/net/wan/sdla_ppp.c Thu Apr 12 12:11:39 2001 @@ -3,14 +3,30 @@ * * Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * 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. * ============================================================================ -* +* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: +* get_ip_address() function has moved +* into the ppp_poll() routine. It cannot +* be called from an interrupt. +* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: +* Deny all and specify allowed requests. +* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown +* option. When the link goes down, the +* network interface IFF_UP flag is reset. +* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. +* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called +* with NULL dev pointer: no check. +* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. +* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels * Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels * Moved dynamic route processing into * a polling routine. @@ -74,13 +90,12 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include <linux/config.h> #include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ @@ -88,24 +103,29 @@ #include <linux/in.h> /* sockaddr_in */ #include <linux/inet.h> /* in_aton(), in_ntoa() prototypes */ -#include <linux/inetdevice.h> -#include <asm/uaccess.h> + +/* ---- 2.4.X KERNEL SUPPORT -----------------------*/ +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> + #include <linux/inetdevice.h> + #include <linux/netdevice.h> +#else + #include <asm/segment.h> + #include <net/route.h> /* Adding new route entries : 2.0.X kernels */ +#endif #include <linux/if.h> +#include <linux/wanpipe.h> #include <linux/sdla_ppp.h> /* PPP firmware API definitions */ #include <linux/sdlasfm.h> /* S514 Type Definition */ /****** Defines & Macros ****************************************************/ -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - #define PPP_DFLT_MTU 1500 /* default MTU */ #define PPP_MAX_MTU 4000 /* maximum MTU */ #define PPP_HDR_LEN 1 +#define MAX_IP_ERRORS 100 + #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ @@ -125,9 +145,10 @@ #define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) #define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) -#define TMR_INT_ENABLED_UPDATE 1 -#define TMR_INT_ENABLED_PPP_EVENT 2 -#define TMR_INT_ENABLED_UDP 4 +#define TMR_INT_ENABLED_UPDATE 0x01 +#define TMR_INT_ENABLED_PPP_EVENT 0x02 +#define TMR_INT_ENABLED_UDP 0x04 +#define TMR_INT_ENABLED_CONFIG 0x20 /* Set Configuraton Command Definitions */ #define PERCENT_TX_BUFF 60 @@ -143,8 +164,11 @@ #define NUM_AUTH_REQ_WITHOUT_REPLY 10 #define END_OFFSET 0x1F0 +#if LINUX_VERSION_CODE < 0x020125 +#define test_and_set_bit set_bit +#define net_ratelimit() 1 +#endif -#define TX_TIMEOUT (5*HZ) /******Data Structures*****************************************************/ @@ -155,9 +179,7 @@ typedef struct ppp_private_area { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + netdevice_t *slave; sdla_t* card; unsigned long router_start_time; /*router start time in sec */ unsigned long tick_counter; /*used for 5 second counter*/ @@ -173,12 +195,20 @@ u32 ip_local; /* Local IP Address */ u32 ip_remote; /* remote IP Address */ + u32 ip_local_tmp; + u32 ip_remote_tmp; + unsigned char timer_int_enabled; /* Who enabled the timer inter*/ unsigned char update_comms_stats; /* Used by update function */ unsigned long curr_trace_addr; /* Trace information */ unsigned long start_trace_addr; unsigned long end_trace_addr; + unsigned char interface_down; /* Brind down interface when channel + goes down */ + unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, + wait a few seconds before configuring */ + unsigned short udp_pkt_lgth; char udp_pkt_src; char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; @@ -191,6 +221,16 @@ unsigned long router_up_time; + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 config_ppp; + u8 ip_error; + }ppp_private_area_t; /* variable for keeping track of enabling/disabling FT1 monitor status */ @@ -203,22 +243,32 @@ /* WAN link driver entry points. These are called by the WAN router module. */ static int update(wan_device_t *wandev); -static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf); -static int del_if(wan_device_t *wandev, struct net_device *dev); +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); /* WANPIPE-specific entry points */ static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); /* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static void if_tx_timeout (struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, +static int if_init(netdevice_t *dev); +static int if_open(netdevice_t *dev); +static int if_close(netdevice_t *dev); +static int if_header(struct sk_buff *skb, netdevice_t *dev, unsigned short type, void *daddr, void *saddr, unsigned len); + +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr(struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); -static int if_send(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *if_stats(netdevice_t *dev); +#else +static struct enet_statistics *if_stats(netdevice_t *dev); +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb); +#endif +static int if_send(struct sk_buff *skb, netdevice_t *dev); /* PPP firmware interface functions */ @@ -229,27 +279,28 @@ static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); static int ppp_comm_enable(sdla_t *card); static int ppp_comm_disable(sdla_t *card); +static int ppp_comm_disable_shutdown(sdla_t *card); static int ppp_get_err_stats(sdla_t *card); static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); -STATIC void wpp_isr(sdla_t *card); +static void wpp_isr(sdla_t *card); static void rx_intr(sdla_t *card); static void event_intr(sdla_t *card); static void timer_intr(sdla_t *card); /* Background polling routines */ static void process_route(sdla_t *card); -static void poll_disconnected(sdla_t *card); +static void retrigger_comm(sdla_t *card); /* Miscellaneous functions */ static int read_info( sdla_t *card ); static int read_connection_info (sdla_t *card); -static int remove_route( sdla_t *card ); -static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card); +static void remove_route( sdla_t *card ); +static int config508(netdevice_t *dev, sdla_t *card); static void show_disc_cause(sdla_t * card, unsigned cause); static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, +static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, ppp_private_area_t *ppp_priv_area); static void init_ppp_tx_rx_buff( sdla_t *card ); static int intr_test( sdla_t *card ); @@ -258,12 +309,20 @@ static void init_global_statistics( sdla_t *card ); static int tokenize(char *str, char **tokens); static char* strstrip(char *str, char *s); -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, struct sk_buff *skb); + +static int config_ppp (sdla_t *); +static void ppp_poll(netdevice_t *); +static void trigger_ppp_poll(netdevice_t *); +static void ppp_poll_delay (unsigned long dev_ptr); + + static int Read_connection_info; static int Intr_test_counter; static unsigned short available_buffer_space; + /* IPX functions */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); @@ -275,12 +334,11 @@ static void s508_unlock (sdla_t *card, unsigned long *smp_flags); static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, ppp_private_area_t* ppp_priv_area ); static unsigned short calc_checksum (char *data, int len); - - - +static void disable_comm (sdla_t *card); +static int detect_and_fix_tx_bug (sdla_t *card); /****** Public Functions ****************************************************/ @@ -298,6 +356,7 @@ */ int wpp_init(sdla_t *card, wandev_conf_t *conf) { + ppp_flags_t *flags; union { char str[80]; @@ -329,6 +388,7 @@ return -EINVAL; } + flags = card->flags; /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was @@ -353,9 +413,10 @@ card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; card->wandev.udp_port = conf->udp_port; card->wandev.ttl = conf->ttl; + card->wandev.state = WAN_DISCONNECTED; + card->disable_comm = &disable_comm; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; card->u.p.authenticator = conf->u.ppp.authenticator; @@ -367,6 +428,33 @@ /* initialize global statistics */ init_global_statistics( card ); + + + if (!card->configured){ + int err; + + Intr_test_counter = 0; + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "%s: Please choose another interrupt\n",card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + card->configured = 1; + } + + ppp_set_intr_mode(card, PPP_INTR_TIMER); + + /* Turn off the transmit and timer interrupt */ + flags->imask &= ~PPP_INTR_TIMER; + + printk(KERN_INFO "\n"); + return 0; } @@ -378,8 +466,8 @@ static int update(wan_device_t *wandev) { sdla_t* card = wandev->private; - struct net_device* dev = card->wandev.dev; - volatile ppp_private_area_t *ppp_priv_area = dev->priv; + netdevice_t* dev; + volatile ppp_private_area_t *ppp_priv_area; ppp_flags_t *flags = card->flags; unsigned long timeout; @@ -390,9 +478,17 @@ if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - //FIXME: Do we need this - if (test_bit(0, (void*)&wandev->critical)) - return -EAGAIN; + /* Shutdown bug fix. This function can be + * called with NULL dev pointer during + * shutdown + */ + if ((dev=card->wandev.dev) == NULL){ + return -ENODEV; + } + + if ((ppp_priv_area=dev->priv) == NULL){ + return -ENODEV; + } ppp_priv_area->update_comms_stats = 2; ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; @@ -427,17 +523,21 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf) +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf) { sdla_t *card = wandev->private; ppp_private_area_t *ppp_priv_area; - + if (wandev->ndev) return -EEXIST; + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", + printk(KERN_INFO "%s: Invalid interface name!\n", card->devname); return -EINVAL; @@ -464,6 +564,14 @@ ppp_priv_area->pap = conf->pap; ppp_priv_area->chap = conf->chap; + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); + printk("%s: Dynamic interface configuration enabled\n", + card->devname); + } + /* If no user ids are specified */ if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ kfree(ppp_priv_area); @@ -494,16 +602,48 @@ ppp_priv_area->enable_IPX = conf->enable_IPX; - if (conf->network_number) + if (conf->network_number){ ppp_priv_area->network_number = conf->network_number; - else + }else{ ppp_priv_area->network_number = 0xDEADBEEF; + } + /* Tells us that if this interface is a + * gateway or not */ + if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,card->u.p.if_name); + } /* prepare network device data space for registration */ - strcpy(dev->name, card->u.p.if_name); + #ifdef LINUX_2_4 + strcpy(dev->name,card->u.p.if_name); + #else + dev->name = (char *)kmalloc(strlen(card->u.p.if_name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", card->u.p.if_name); + #endif + dev->init = &if_init; dev->priv = ppp_priv_area; + dev->mtu = min(dev->mtu, card->wandev.mtu); + + /* Initialize the polling task routine */ + #ifndef LINUX_2_4 + ppp_priv_area->poll_task.next = NULL; + #endif + ppp_priv_area->poll_task.sync=0; + ppp_priv_area->poll_task.routine = (void*)(void*)ppp_poll; + ppp_priv_area->poll_task.data = dev; + + /* Initialize the polling delay timer */ + init_timer(&ppp_priv_area->poll_delay_timer); + ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; + ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; + + + /* Since we start with dummy IP addresses we can say + * that route exists */ + printk(KERN_INFO "\n"); return 0; } @@ -511,17 +651,17 @@ /*============================================================================ * Delete logical channel. */ -static int del_if(wan_device_t *wandev, struct net_device *dev) +static int del_if(wan_device_t *wandev, netdevice_t *dev) { - if (dev->priv) { - - kfree(dev->priv); - dev->priv = NULL; - } - return 0; } +static void disable_comm (sdla_t *card) +{ + ppp_comm_disable_shutdown(card); + return; +} + /****** WANPIPE-specific entry points ***************************************/ /*============================================================================ @@ -534,6 +674,7 @@ ppp_mbox_t *mbox = card->mbox; int len; +#if defined(LINUX_2_1) || defined(LINUX_2_4) if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) return -EFAULT; @@ -558,6 +699,35 @@ if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; +#else + + if (!u_cmd || verify_area(VERIFY_WRITE, u_cmd, sizeof(ppp_cmd_t))) + return -EFAULT; + + memcpy_fromfs((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t)); + + len = mbox->cmd.length; + + if (len) { + + if (!u_data || verify_area(VERIFY_READ, u_data, len)) + return -EFAULT; + } + + /* execute command */ + if (!sdla_exec(mbox)) + return -EIO; + + /* return result */ + memcpy_tofs(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t)); + len = mbox->cmd.length; + + if (len && u_data && !verify_area(VERIFY_WRITE, u_data, len)) + memcpy_tofs(u_data, (void*)&mbox->data, len); + + +#endif + return 0; } @@ -570,14 +740,14 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct net_device *dev) +static int if_init(netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; wan_device_t *wandev = &card->wandev; -#ifndef LINUX_2_1 + #ifdef LINUX_2_0 int i; -#endif + #endif /* Initialize device driver entry points */ dev->open = &if_open; @@ -586,21 +756,24 @@ dev->rebuild_header = &if_rebuild_hdr; dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; + #ifdef LINUX_2_4 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + #endif /* Initialize media-specific parameters */ dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; /* Enable Mulitcasting if specified by user*/ if (ppp_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; + dev->flags |= IFF_MULTICAST; } -#ifndef LINUX_2_1 + #ifdef LINUX_2_0 dev->family = AF_INET; -#endif + #endif dev->mtu = wandev->mtu; dev->hard_header_len = PPP_HDR_LEN; /* media header length */ @@ -615,7 +788,13 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) dev_init_buffers(dev); + #else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); + #endif + return 0; } @@ -626,105 +805,44 @@ * * Return 0 if O.k. or errno. */ -static int if_open(struct net_device *dev) +static int if_open (netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - ppp_flags_t *flags = card->flags; struct timeval tv; - int err = 0; - - if (netif_running(dev)) - return -EBUSY; /* only one open is allowed */ - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - if (!card->configured){ - - if (config508(ppp_priv_area, card)){ - - err = -EIO; - card->wandev.critical = 0; - return err; - } - - Intr_test_counter = 0; - err = intr_test( card ); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk("%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk( "%s: Please choose another interrupt\n",card->devname); - err = -EIO; - card->wandev.critical = 0; - return err; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - card->configured = 1; - - } - - /* Initialize Rx/Tx buffer control fields */ - init_ppp_tx_rx_buff( card ); - - if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| - PPP_INTR_TXRDY| - PPP_INTR_MODEM| - PPP_INTR_CMD | - PPP_INTR_DISC | - PPP_INTR_OPEN | - PPP_INTR_DROP_DTR | - PPP_INTR_TIMER)) { - - err = -EIO; - card->wandev.critical = 0; - return err; + //unsigned long smp_flags; - } - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; + if (is_dev_running(dev)) + return -EBUSY; - /* If you are not the authenticator and any one of the protocol is - * enabled then we call the set_out_bound_authentication. - */ - if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ - err = -EIO; - card->wandev.critical = 0; - return err; - } - } - - /* If you are the authenticator and any one of the protocol is enabled - * then we call the set_in_bound_authentication. - */ - if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){ - err = -EIO; - card->wandev.critical = 0; - return err; - } - } + wanpipe_open(card); - if (ppp_comm_enable(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } + #ifdef LINUX_2_4 + netif_start_queue(dev); + #else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + #endif - wanpipe_set_state(card, WAN_CONNECTING); - wanpipe_open(card); - dev->mtu = min(dev->mtu, card->wandev.mtu); - netif_start_queue(dev); do_gettimeofday( &tv ); ppp_priv_area->router_start_time = tv.tv_sec; - card->wandev.critical = 0; - return err; + /* We cannot configure the card here because we don't + * have access to the interface IP addresses. + * Once the interface initilization is complete, we will be + * able to access the IP addresses. Therefore, + * configure the ppp link in the poll routine */ + set_bit(0,&ppp_priv_area->config_ppp); + ppp_priv_area->config_wait_timeout=jiffies; + + /* Start the PPP configuration after 1sec delay. + * This will give the interface initilization time + * to finish its configuration */ + del_timer(&ppp_priv_area->poll_delay_timer); + ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&ppp_priv_area->poll_delay_timer); + return 0; } /*============================================================================ @@ -732,20 +850,18 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ -static int if_close(struct net_device *dev) +static int if_close(netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - netif_stop_queue(dev); + stop_net_queue(dev); + #ifndef LINUX_2_4 + dev->start=0; + #endif wanpipe_close(card); - wanpipe_set_state(card, WAN_DISCONNECTED); - ppp_set_intr_mode(card, 0); - ppp_comm_disable(card); - card->wandev.critical = 0; + + del_timer (&ppp_priv_area->poll_delay_timer); return 0; } @@ -758,13 +874,12 @@ * * Return: media header length. */ -static int if_header(struct sk_buff *skb, struct net_device *dev, +static int if_header(struct sk_buff *skb, netdevice_t *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { switch (type) { case ETH_P_IP: - case ETH_P_IPX: skb->protocol = htons(type); break; @@ -782,10 +897,10 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - +#if defined(LINUX_2_1) || defined(LINUX_2_4) static int if_rebuild_hdr (struct sk_buff *skb) { - struct net_device *dev = skb->dev; + netdevice_t *dev = skb->dev; ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; @@ -794,33 +909,39 @@ return 1; } +#else +static int if_rebuild_hdr (void* hdr, netdevice_t* dev, unsigned long raddr, + struct sk_buff* skb) +{ + return 1; + +} +#endif +#ifdef LINUX_2_4 /*============================================================================ - * Handle transmit timeout from netif watchdog + * Handle transmit timeout event from netif watchdog */ -static void if_tx_timeout (struct net_device *dev) +static void if_tx_timeout (netdevice_t *dev) { - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - + ppp_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. */ - ++ppp_priv_area->if_send_stat.if_send_tbusy; + ++ chan->if_send_stat.if_send_tbusy; ++card->wandev.stats.collisions; - printk (KERN_INFO "%s: Transmit times out\n", card->devname); - - ++ppp_priv_area->if_send_stat.if_send_tbusy_timeout; - ++card->wandev.stats.collisions; - - /* unbusy the card (because only one interface per card) */ - netif_wake_queue(dev); + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + ++chan->if_send_stat.if_send_tbusy_timeout; + netif_wake_queue (dev); } +#endif + /*============================================================================ @@ -840,19 +961,22 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int if_send (struct sk_buff *skb, struct net_device *dev) +static int if_send (struct sk_buff *skb, netdevice_t *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; unsigned char *sendpacket; unsigned long smp_flags; ppp_flags_t *flags = card->flags; - int retry = 0; int udp_type; - + int err=0; ++ppp_priv_area->if_send_stat.if_send_entry; + #ifdef LINUX_2_4 + netif_stop_queue(dev); + #endif + if (skb == NULL) { /* If we get here, some higher layer thinks we've missed an @@ -862,12 +986,37 @@ card->devname, dev->name); ++ppp_priv_area->if_send_stat.if_send_skb_null; - - netif_wake_queue(dev); + + wake_net_dev(dev); return 0; - } + #ifndef LINUX_2_4 + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++ppp_priv_area->if_send_stat.if_send_tbusy; + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit times out on %s\n",card->devname,dev->name); + + ++ppp_priv_area->if_send_stat.if_send_tbusy_timeout; + ++card->wandev.stats.collisions; + + /* unbusy the card (because only one interface per card)*/ + dev->tbusy = 0; + } + #endif + sendpacket = skb->data; udp_type = udp_pkt_type( skb, card ); @@ -879,15 +1028,18 @@ flags->imask |= PPP_INTR_TIMER; } ++ppp_priv_area->if_send_stat.if_send_PIPE_request; + start_net_queue(dev); return 0; - } /* Check for broadcast and multicast addresses * If found, drop (deallocate) a packet and return. */ if(chk_bcast_mcast_addr(card, dev, skb)){ - return 0; + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; } @@ -895,31 +1047,28 @@ s508_lock(card,&smp_flags); } - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); - dev_kfree_skb(skb); - + ++card->wandev.stats.tx_dropped; ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; - - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return 0; + start_net_queue(dev); + goto if_send_exit_crit; } if (card->wandev.state != WAN_CONNECTED) { ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; ++card->wandev.stats.tx_dropped; - + start_net_queue(dev); + } else if (!skb->protocol) { ++ppp_priv_area->if_send_stat.if_send_protocol_error; ++card->wandev.stats.tx_errors; - + start_net_queue(dev); + } else { /*If it's IPX change the network numbers to 0 if they're ours.*/ @@ -929,37 +1078,45 @@ ppp_priv_area->network_number, 0); } else { ++card->wandev.stats.tx_dropped; - goto tx_done; + start_net_queue(dev); + goto if_send_exit_crit; } } if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - retry = 1; - netif_stop_queue(dev); + stop_net_queue(dev); ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; - ppp_priv_area->tick_counter = jiffies; - flags->imask |= 0x02; /* unmask Tx interrupts */ } else { ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; ++card->wandev.stats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.tx_bytes += skb->len; + #endif + start_net_queue(dev); + #ifdef LINUX_2_4 + dev->trans_start = jiffies; + #endif + + } } -tx_done: - if (!retry){ - dev_kfree_skb(skb); +if_send_exit_crit: + + if (!(err=is_queue_stopped(dev))){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + ppp_priv_area->tick_counter = jiffies; + flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ } - - card->wandev.critical = 0; + clear_bit(SEND_CRIT,&card->wandev.critical); if(card->hw.type != SDLA_S514){ s508_unlock(card,&smp_flags); } - - return retry; + return err; } @@ -968,7 +1125,7 @@ */ static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, + struct sk_buff *skb, netdevice_t* dev, ppp_private_area_t* ppp_priv_area ) { int udp_pkt_stored = 0; @@ -982,8 +1139,13 @@ udp_pkt_stored = 1; }else{ if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ +#if defined(LINUX_2_1) || defined(LINUX_2_4) printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", card->devname, skb->len); +#else + printk(KERN_INFO "%s: PIPEMON UDP request too long : %li\n", + card->devname, skb->len); +#endif }else{ printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", card->devname); @@ -991,7 +1153,12 @@ ppp_priv_area->udp_pkt_lgth = 0; } - dev_kfree_skb(skb); + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + return(udp_pkt_stored); } @@ -1157,7 +1324,11 @@ * Get ethernet-style interface statistics. * Return a pointer to struct net_device_stats. */ -static struct net_device_stats *if_stats(struct net_device *dev) +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats *if_stats(netdevice_t *dev) +#else +static struct enet_statistics *if_stats(netdevice_t *dev) +#endif { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -1354,7 +1525,7 @@ /* If timer has been enabled, set the timer delay to 1sec */ if (mode & 0x80){ - ppp_intr_data->timer_len = 5;//100; //250; + ppp_intr_data->timer_len = 250; //5;//100; //250; mb->cmd.length = 4; } @@ -1382,7 +1553,9 @@ if (err != CMD_OK) ppp_error(card, err, mb); - + else + card->u.p.comm_enabled = 1; + return err; } @@ -1399,10 +1572,46 @@ err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; if (err != CMD_OK) ppp_error(card, err, mb); + else + card->u.p.comm_enabled = 0; return err; } +static int ppp_comm_disable_shutdown(sdla_t *card) +{ + ppp_mbox_t *mb = card->mbox; + ppp_intr_info_t *ppp_intr_data; + int err; + + if (!mb){ + return 1; + } + + ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; + + /* Disable all interrupts */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + ppp_intr_data->i_enable = 0; + + ppp_intr_data->irq = card->hw.irq; + mb->cmd.length = 2; + + mb->cmd.command = PPP_SET_INTR_FLAGS; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + /* Disable communicatinons */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_COMM_DISABLE; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + card->u.p.comm_enabled = 0; + + return 0; +} + + + /*============================================================================ * Get communications error statistics. */ @@ -1495,36 +1704,40 @@ /*============================================================================ * PPP interrupt service routine. */ -STATIC void wpp_isr(sdla_t *card) +static void wpp_isr (sdla_t *card) { ppp_flags_t *flags = card->flags; char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - - + netdevice_t *dev = card->wandev.dev; int i; card->in_isr = 1; - ++card->statistics.isr_entry; - //FIXME: Do we need this - card->force_enable_irq = 0; - + if (!dev && flags->iflag != PPP_INTR_CMD){ + card->in_isr = 0; + flags->iflag = 0; + return; + } + + if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + card->in_isr = 0; + flags->iflag = 0; + return; + } + + if(card->hw.type != SDLA_S514){ - if (test_and_set_bit(0, (void*)&card->wandev.critical)) { - + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { ++card->statistics.isr_already_critical; printk (KERN_INFO "%s: Critical while in ISR!\n", card->devname); card->in_isr = 0; + flags->iflag = 0; return; - } } - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) { case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ @@ -1535,8 +1748,7 @@ case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ ++card->statistics.isr_tx; flags->imask &= ~PPP_INTR_TXRDY; - netif_wake_queue (dev); - card->buff_int_mode_unbusy = 1; + wake_net_dev(dev); break; case PPP_INTR_CMD: /* interface command completed */ @@ -1567,10 +1779,7 @@ card->in_isr = 0; flags->iflag = 0; - card->wandev.critical = 0; - - if(card->buff_int_mode_unbusy) - netif_wake_queue(dev); + return; } /*============================================================================ @@ -1579,7 +1788,7 @@ static void rx_intr(sdla_t *card) { ppp_buf_ctl_t *rxbuf = card->rxmb; - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; ppp_private_area_t *ppp_priv_area; struct sk_buff *skb; unsigned len; @@ -1603,11 +1812,21 @@ printk(KERN_INFO "\n"); ++card->statistics.rx_intr_corrupt_rx_bfr; - return; - } - if (dev && netif_running(dev)) { + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it means that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + ppp_set_intr_mode(card,0); + return; + } + + if (dev && is_dev_running(dev) && dev->priv){ len = rxbuf->length; ppp_priv_area = dev->priv; @@ -1662,9 +1881,12 @@ /* Handle an IPXWAN packet */ if( ppp_priv_area->enable_IPX) { - ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); - dev_kfree_skb(skb); - + + /* Make sure we are not already sending */ + if (!test_bit(SEND_CRIT, &card->wandev.critical)){ + ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); + } + wan_dev_kfree_skb(skb,FREE_READ); } else { ++card->wandev.stats.rx_dropped; @@ -1675,15 +1897,19 @@ skb->mac.raw = skb->data; ++card->wandev.stats.rx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.rx_bytes += skb->len; + #endif ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; netif_rx(skb); } } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); + + if (net_ratelimit()){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } ++card->wandev.stats.rx_dropped; ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; } @@ -1703,16 +1929,18 @@ void event_intr (sdla_t *card) { - struct net_device* dev = card->wandev.dev; + netdevice_t* dev = card->wandev.dev; ppp_private_area_t* ppp_priv_area = dev->priv; volatile ppp_flags_t *flags = card->flags; switch (flags->iflag){ case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", - card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); + if (net_ratelimit()){ + printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", + card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); + } break; case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ @@ -1723,15 +1951,16 @@ if (flags->disc_cause & (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | PPP_REMOTE_TERMINATION)) { + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - Read_connection_info = 1; - remove_route (card); + set_bit(0,&Read_connection_info); } wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; flags->imask |= PPP_INTR_TIMER; + trigger_ppp_poll(dev); } break; @@ -1743,30 +1972,68 @@ if (flags->lcp_state == 0x09 && (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ + /* Initialize the polling timer and set the state - * to WAN_CONNNECTED - */ - card->state_tick = jiffies; - wanpipe_set_state(card, WAN_CONNECTED); - ppp_priv_area->timer_int_enabled |= + * to WAN_CONNNECTED */ + + + /* BUG FIX: When the protocol restarts, during heavy + * traffic, board tx buffers and driver tx buffers + * can go out of sync. This checks the condition + * and if the tx buffers are out of sync, the + * protocols are restarted. + * I don't know why the board tx buffer is out + * of sync. It could be that a packets is tx + * while the link is down, but that is not + * possible. The other possiblility is that the + * firmware doesn't reinitialize properly. + * FIXME: A better fix should be found. + */ + if (detect_and_fix_tx_bug(card)){ + + ppp_comm_disable(card); + + wanpipe_set_state(card, WAN_DISCONNECTED); + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + flags->imask |= PPP_INTR_TIMER; + break; + } + + card->state_tick = jiffies; + wanpipe_set_state(card, WAN_CONNECTED); + + NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", + (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, + (unsigned long)card->rxmb, *card->u.p.rxbuf_next); + + /* Tell timer interrupt that PPP event occured */ + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; flags->imask |= PPP_INTR_TIMER; + /* If we are in PEER mode, we must first obtain the + * IP information and then go into the poll routine */ + if (card->u.p.ip_mode != WANOPT_PPP_PEER){ + trigger_ppp_poll(dev); + } } break; case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - Read_connection_info = 1; - remove_route (card); + set_bit(0,&Read_connection_info); } + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; flags->imask |= PPP_INTR_TIMER; + trigger_ppp_poll(dev); break; default: @@ -1781,10 +2048,18 @@ void timer_intr (sdla_t *card) { - struct net_device* dev = card->wandev.dev; + netdevice_t* dev = card->wandev.dev; ppp_private_area_t* ppp_priv_area = dev->priv; ppp_flags_t *flags = card->flags; + + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ + if (!config_ppp(card)){ + ppp_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_CONFIG; + } + } + /* Update statistics */ if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ ppp_get_err_stats(card); @@ -1801,12 +2076,11 @@ ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; } - /* PPP Event */ if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ if (card->wandev.state == WAN_DISCONNECTED){ - poll_disconnected(card); + retrigger_comm(card); } /* If the state is CONNECTING, it means that communicatins were @@ -1823,21 +2097,22 @@ * poll for an IP address which will be provided by remote end. */ else if ((card->wandev.state == WAN_CONNECTED && - card->u.p.ip_mode == WANOPT_PPP_PEER) && - Read_connection_info){ + card->u.p.ip_mode == WANOPT_PPP_PEER) && + test_bit(0,&Read_connection_info)){ card->state_tick = jiffies; - if (!read_connection_info (card)){ - card->poll = &process_route; + if (read_connection_info (card)){ + printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", + card->devname); + }else{ + clear_bit(0,&Read_connection_info); + set_bit(1,&Read_connection_info); + trigger_ppp_poll(dev); } - }else{ - /* If we are using Static IP,no need to poll for - * an IP address. - */ - NEX_PRINTK(KERN_INFO "Turning off TIMER \n"); + //FIXME Put the comment back int ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } + } }/* End of PPP_EVENT */ @@ -1970,32 +2245,62 @@ static void process_route (sdla_t *card) { ppp_flags_t *flags = card->flags; - struct net_device *dev = card->wandev.dev; - struct in_device *in_dev = dev->ip_ptr; + netdevice_t *dev = card->wandev.dev; + ppp_private_area_t *ppp_priv_area = dev->priv; - if (in_dev != NULL ) { - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - (Read_connection_info && flags->ip_state == 0x09)){ - - printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); - if (read_info( card )) { - printk(KERN_INFO - "%s: An error occurred in IP assignment.\n", - card->devname); - } else { +#if defined(LINUX_2_1) || defined(LINUX_2_4) + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + (flags->ip_state == 0x09)){ + + /* We get ip_local from the firmware in PEER mode. + * Therefore, if ip_local is 0, we failed to obtain + * the remote IP address. */ + if (ppp_priv_area->ip_local == 0) + return; + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO + "%s: An error occurred in IP assignment.\n", + card->devname); + } else { + struct in_device *in_dev = dev->ip_ptr; + if (in_dev != NULL ) { struct in_ifaddr *ifa = in_dev->ifa_list; printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", - card->devname, in_ntoa(ifa->ifa_local)); + card->devname, in_ntoa(ifa->ifa_local)); printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_address)); + }else{ + printk(KERN_INFO + "%s: Error: Failed to add a route for PPP interface %s\n", + card->devname,dev->name); } - Read_connection_info = 0; } - }else{ - printk(KERN_INFO "%s: Error: Null pointer in Poll Active\n", + } +#else + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + (flags->ip_state == 0x09)){ + + if (ppp_priv_area->ip_local == 0) + return; + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO + "%s: An error occurred in IP assignment.\n", card->devname); + } else { + printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", + card->devname, in_ntoa(dev->pa_addr)); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", + card->devname, in_ntoa(dev->pa_dstaddr)); + } } - card->poll = NULL; + +#endif } @@ -2004,19 +2309,17 @@ * o if interface is up and the hold-down timeout has expired, then retry * connection. */ -static void poll_disconnected(sdla_t *card) +static void retrigger_comm(sdla_t *card) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; + + if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - if (dev && netif_running(dev) && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - wanpipe_set_state(card, WAN_CONNECTING); - + if(ppp_comm_enable(card) == CMD_OK){ init_ppp_tx_rx_buff( card ); } - } } @@ -2025,12 +2328,14 @@ /*============================================================================ * Configure S508 adapter. */ -static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card) +static int config508(netdevice_t *dev, sdla_t *card) { ppp508_conf_t cfg; - struct net_device *dev = card->wandev.dev; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev = dev->ip_ptr; - +#endif + ppp_private_area_t *ppp_priv_area = dev->priv; + /* Prepare PPP configuration structure */ memset(&cfg, 0, sizeof(ppp508_conf_t)); @@ -2040,6 +2345,7 @@ if (card->wandev.interface == WANOPT_RS232) cfg.conf_flags |= INTERFACE_LEVEL_RS232; + cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ cfg.mtu_local = card->wandev.mtu; @@ -2065,6 +2371,7 @@ card->devname); cfg.auth_options = INBOUND_AUTH; } + if( ppp_priv_area->pap == WANOPT_YES){ cfg.auth_options |=PAP_AUTH; printk(KERN_INFO "%s: Pap enabled\n", card->devname); @@ -2076,6 +2383,7 @@ if (ppp_priv_area->enable_IPX == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; }else{ cfg.ipx_options = DISABLE_IPX; @@ -2085,25 +2393,92 @@ case WANOPT_PPP_STATIC: + printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); cfg.ip_options = L_AND_R_IP_NO_ASSIG | ENABLE_IP; +#if defined(LINUX_2_1) || defined(LINUX_2_4) cfg.ip_local = in_dev->ifa_list->ifa_local; cfg.ip_remote = in_dev->ifa_list->ifa_address; +#else + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; +#endif + + /* Debugging code used to check that IP addresses + * obtained from the kernel are correct */ + + { + char laddr[20]; + char raddr[20]; + strcpy(laddr,in_ntoa(cfg.ip_local)); + strcpy(raddr,in_ntoa(cfg.ip_remote)); + NEX_PRINTK(KERN_INFO "Local %s Remote %s Name %s\n", - in_ntoa(cfg.ip_local), - in_ntoa(cfg.ip_remote), - dev->name); + laddr,raddr, dev->name); + + } + break; + + case WANOPT_PPP_HOST: + + printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); + cfg.ip_options = L_IP_LOCAL_ASSIG | + R_IP_LOCAL_ASSIG | + ENABLE_IP; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + cfg.ip_local = in_dev->ifa_list->ifa_local; + cfg.ip_remote = in_dev->ifa_list->ifa_address; + #else + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; + #endif + + /* Debugging code used to check that IP addresses + * obtained from the kernel are correct */ + { + char laddr[20]; + char raddr[20]; + strcpy(laddr,in_ntoa(cfg.ip_local)); + strcpy(raddr,in_ntoa(cfg.ip_remote)); + + NEX_PRINTK (KERN_INFO "Local %s Remote %s Name %s\n", + laddr,raddr, dev->name); + + } + + break; case WANOPT_PPP_PEER: + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + + printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); cfg.ip_options = L_IP_REMOTE_ASSIG | R_IP_REMOTE_ASSIG | ENABLE_IP; cfg.ip_local = 0x00; cfg.ip_remote = 0x00; break; - + + #else + + /* No PEER support for 2.0.X kernels, drop down to default + * condition */ + + printk(KERN_INFO "%s: ERROR, PEER mode is not supported in 2.0.X kernels\n", + card->devname); + + #endif + + default: + printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n", + card->devname); + printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", + card->devname); + return 1; } + return ppp_configure(card, &cfg); } @@ -2168,7 +2543,7 @@ /*============================================================================= * Process UDP call of type PTPIPEAB. */ -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, +static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char buf2[5]; @@ -2186,33 +2561,31 @@ memcpy(&buf2, &card->wandev.udp_port, 2 ); - switch(ppp_udp_pkt->cblock.command) { + if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* PPIPE_ENABLE_TRACING */ - case PPIPE_ENABLE_TRACING: - - /* PPIPE_DISABLE_TRACING */ - case PPIPE_DISABLE_TRACING: - - /* PPIPE_GET_TRACE_INFO */ - case PPIPE_GET_TRACE_INFO: - - /* SET FT1 MODE */ - case SET_FT1_MODE: - if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - ++ppp_priv_area->pipe_mgmt_stat. - UDP_PIPE_mgmt_direction_err; + switch(ppp_udp_pkt->cblock.command) { + + case PPIPE_GET_IBA_DATA: + case PPP_READ_CONFIG: + case PPP_GET_CONNECTION_INFO: + case PPIPE_ROUTER_UP_TIME: + case PPP_READ_STATISTICS: + case PPP_READ_ERROR_STATS: + case PPP_READ_PACKET_STATS: + case PPP_READ_LCP_STATS: + case PPP_READ_IPCP_STATS: + case PPP_READ_IPXCP_STATS: + case PPP_READ_PAP_STATS: + case PPP_READ_CHAP_STATS: + case PPP_READ_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + + default: udp_mgmt_req_valid = 0; - } - break; - - default: - break; - } + break; + } + } if(!udp_mgmt_req_valid) { @@ -2221,7 +2594,13 @@ /* set return code */ ppp_udp_pkt->cblock.result = 0xCD; - + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,ppp_udp_pkt->cblock.command); + } } else { /* Initialize the trace element */ trace_element_t trace_element; @@ -2422,27 +2801,24 @@ /* set return code */ ppp_udp_pkt->cblock.result = 0x00; - - break; - - /* PPIPE_KILL_BOARD */ - case PPIPE_KILL_BOARD: + ppp_udp_pkt->cblock.result = 0; break; /* PPIPE_FT1_READ_STATUS */ case PPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data, 2); - ppp_udp_pkt->cblock.length = 2; + sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); + ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 2; break; case PPIPE_FLUSH_DRIVER_STATS: init_ppp_priv_struct( ppp_priv_area ); init_global_statistics( card ); mbox->cmd.length = 0; + ppp_udp_pkt->cblock.result = 0; break; + case PPIPE_ROUTER_UP_TIME: do_gettimeofday( &tv ); @@ -2450,34 +2826,11 @@ ppp_priv_area->router_start_time; *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; mbox->cmd.length = 4; + ppp_udp_pkt->cblock.result = 0; break; - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* Enable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 1) { - - if( rCount++ != 0 ) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* PPIPE_DRIVER_STATISTICS */ + /* PPIPE_DRIVER_STATISTICS */ case PPIPE_DRIVER_STAT_IFSEND: - printk(KERN_INFO "Getting IF_SEND Drivers Statistics\n"); memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, sizeof(if_send_stat_t)); @@ -2515,8 +2868,38 @@ mbox->cmd.length = ppp_udp_pkt->cblock.length; break; + + /* FT1 MONITOR STATUS */ + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if( ppp_udp_pkt->data[0] == 1) { + + if( rCount++ != 0 ) { + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( ppp_udp_pkt->data[0] == 0) { + + if( --rCount != 0) { + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + goto udp_dflt_cmd; + + /* WARNING: FIXME: This should be fixed. + * The FT1 Status Ctrl doesn't have a break + * statment. Thus, no code must be inserted + * HERE: between default and above case statement */ + default: +udp_dflt_cmd: /* it's a board command */ mbox->cmd.command = ppp_udp_pkt->cblock.command; @@ -2555,9 +2938,12 @@ len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; - ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); + + /* Make sure we are not already sending */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)){ + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; + ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); + } } else { @@ -2587,6 +2973,8 @@ } ppp_priv_area->udp_pkt_lgth = 0; + + return; } /*============================================================================= @@ -2648,9 +3036,12 @@ (info->rxb_num - 1); } + card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; + card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; + card->u.p.rx_base = info->rxb_base; card->u.p.rx_top = info->rxb_end; - + card->u.p.txbuf = card->u.p.txbuf_base; card->rxmb = card->u.p.rxbuf_base; @@ -2662,21 +3053,32 @@ */ static int read_info( sdla_t *card ) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; ppp_private_area_t *ppp_priv_area = dev->priv; int err; + + #if defined(LINUX_2_1) || defined(LINUX_2_4) struct ifreq if_info; struct sockaddr_in *if_data1, *if_data2; mm_segment_t fs; + #else + #ifdef _DYNAMIC_ROUTE_20X_SUPPORT_ + struct rtentry route; + #endif + #endif + + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Set Local and remote addresses */ memset(&if_info, 0, sizeof(if_info)); strcpy(if_info.ifr_name, dev->name); + fs = get_fs(); set_fs(get_ds()); /* get user space block */ - /* Change the local and remote ip address of the interface. * This will also add in the destination route. */ @@ -2690,11 +3092,43 @@ err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); set_fs(fs); /* restore old block */ + +#else + /* FIXME: Dynamic Routing in 2.0.X kernels is not + * supported. Sorry ! I'll come back to it when I get + * a chance. */ + + printk(KERN_INFO "%s: ERROR, Dynamic routing is not supported in 2.0.X kernels\n", + card->devname); + printk(KERN_INFO "%s: Please use the STATIC IP mode!\n", + card->devname); + err = 0; + + #ifdef _DYNAMIC_ROUTE_20X_SUPPORT_ + dev->pa_dstaddr = ppp_priv_area->ip_remote; + dev->pa_addr = ppp_priv_area->ip_local; + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + ((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr = + dev->pa_dstaddr; + ((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr = + 0xFFFFFFFF; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_family = + AF_INET; + + err = ip_rt_new(&route); + + #endif + +#endif if (err) { - printk (KERN_INFO "%s: Adding of route failed:\n", - card->devname); + printk (KERN_INFO "%s: Adding of route failed: %i\n", + card->devname,err); printk (KERN_INFO "%s: Local : %s\n", card->devname,in_ntoa(ppp_priv_area->ip_local)); printk (KERN_INFO "%s: Remote: %s\n", @@ -2708,31 +3142,39 @@ * Called when ppp interface disconnected. */ -static int remove_route( sdla_t *card ) +static void remove_route( sdla_t *card ) { - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; long ip_addr; int err; +#if defined(LINUX_2_1) || defined(LINUX_2_4) mm_segment_t fs; struct ifreq if_info; struct sockaddr_in *if_data1; struct in_device *in_dev = dev->ip_ptr; struct in_ifaddr *ifa = in_dev->ifa_list; +#else + unsigned long fs = 0; + struct rtentry route; +#endif +#if defined(LINUX_2_1) || defined(LINUX_2_4) ip_addr = ifa->ifa_local; /* Set Local and remote addresses */ memset(&if_info, 0, sizeof(if_info)); strcpy(if_info.ifr_name, dev->name); +#endif fs = get_fs(); set_fs(get_ds()); /* get user space block */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* Change the local ip address of the interface to 0. * This will also delete the destination route. */ @@ -2740,6 +3182,26 @@ if_data1->sin_addr.s_addr = 0; if_data1->sin_family = AF_INET; err = devinet_ioctl( SIOCSIFADDR, &if_info ); +#else + + ip_addr = dev->pa_addr; + dev->pa_dstaddr = 0; + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + ((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr = + dev->pa_dstaddr; + ((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr = + 0xFFFFFFFF; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_family = + AF_INET; + + + err = ip_rt_kill(&route); + +#endif set_fs(fs); /* restore old block */ @@ -2747,13 +3209,12 @@ if (err) { printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", card->devname, err); - return err; - }else - printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfully\n", + return; + }else{ + printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n", card->devname, in_ntoa(ip_addr)); - - - return 0; + } + return; } /*============================================================================= @@ -2765,13 +3226,6 @@ ppp_mbox_t *mb = card->mbox; int err,i; - /* The critical flag is unset because during intialization (if_open) - * we want the interrupts to be enabled so that when the wpp_isr is - * called it does not exit due to critical flag set. - */ - - card->wandev.critical = 0; - err = ppp_set_intr_mode( card, 0x08 ); if (err == CMD_OK) { @@ -2792,7 +3246,6 @@ if (err != CMD_OK) return err; - card->wandev.critical = 1; return 0; } @@ -2803,7 +3256,6 @@ { unsigned char *sendpacket; unsigned char buf2[5]; - //FIXME: Use the structure ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; sendpacket = skb->data; @@ -2850,16 +3302,19 @@ * multicast source IP address. */ -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, struct sk_buff *skb) { u32 src_ip_addr; u32 broadcast_ip_addr = 0; + #if defined(LINUX_2_1) || defined(LINUX_2_4) struct in_device *in_dev; + #endif /* read the IP source address from the outgoing packet */ src_ip_addr = *(u32 *)(skb->data + 12); /* read the IP broadcast address for the device */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa= in_dev->ifa_list; @@ -2868,13 +3323,14 @@ else return 0; } + #else + broadcast_ip_addr = dev->pa_brdaddr; + #endif /* check if the IP Source Address is a Broadcast address */ if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++card->wandev.stats.tx_dropped; return 1; } @@ -2883,8 +3339,6 @@ (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", card->devname); - dev_kfree_skb(skb); - ++card->wandev.stats.tx_dropped; return 1; } @@ -2893,26 +3347,26 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags) { -#ifdef CONFIG_SMP - spin_lock_irqsave(&card->lock, *smp_flags); -#else + #if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + #else disable_irq(card->hw.irq); -#endif + #endif } void s508_unlock (sdla_t *card, unsigned long *smp_flags) { -#ifdef CONFIG_SMP - spin_unlock_irqrestore(&card->lock, *smp_flags); -#else + #if defined(__SMP__) || defined(LINUX_2_4) + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); + #else enable_irq(card->hw.irq); -#endif + #endif } static int read_connection_info (sdla_t *card) { ppp_mbox_t *mb = card->mbox; - struct net_device *dev = card->wandev.dev; + netdevice_t *dev = card->wandev.dev; ppp_private_area_t *ppp_priv_area = dev->priv; ppp508_connect_info_t *ppp508_connect_info; int err; @@ -2924,15 +3378,347 @@ if (err != CMD_OK) { ppp_error(card, err, mb); + ppp_priv_area->ip_remote = 0; + ppp_priv_area->ip_local = 0; } else { ppp508_connect_info = (ppp508_connect_info_t *)mb->data; - ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; ppp_priv_area->ip_local = ppp508_connect_info->ip_local; + + NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", + ppp_priv_area->ip_remote, + ppp_priv_area->ip_local); } return err; } + +/*=============================================================================== + * config_ppp + * + * Configure the ppp protocol and enable communications. + * + * The if_open function binds this function to the poll routine. + * Therefore, this function will run every time the ppp interface + * is brought up. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + */ +static int config_ppp (sdla_t *card) +{ + + netdevice_t *dev = card->wandev.dev; + ppp_flags_t *flags = card->flags; + ppp_private_area_t *ppp_priv_area = dev->priv; + + if (card->u.p.comm_enabled){ + + if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || + ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ + + /* The IP addersses have changed, we must + * stop the communications and reconfigure + * the card. Reason: the firmware must know + * the local and remote IP addresses. */ + disable_comm(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO + "%s: IP addresses changed!\n", + card->devname); + printk(KERN_INFO "%s: Restarting communications ...\n", + card->devname); + }else{ + /* IP addresses are the same and the link is up, + * we dont have to do anything here. Therefore, exit */ + return 0; + } + } + + /* Record the new IP addreses */ + ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; + ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; + + if (config508(dev, card)){ + printk(KERN_INFO "%s: Failed to configure PPP device\n", + card->devname); + return 0; + } + + if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| + PPP_INTR_TXRDY| + PPP_INTR_MODEM| + PPP_INTR_DISC | + PPP_INTR_OPEN | + PPP_INTR_DROP_DTR | + PPP_INTR_TIMER)) { + + printk(KERN_INFO "%s: Failed to configure board interrupts !\n", + card->devname); + return 0; + } + + /* Turn off the transmit and timer interrupt */ + flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; + + + /* If you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + printk(KERN_INFO "%s: Outbound authentication failed !\n", + card->devname); + return 0; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ + if (ppp_set_inbnd_auth(card, ppp_priv_area)){ + printk(KERN_INFO "%s: Inbound authentication failed !\n", + card->devname); + return 0; + } + } + + /* If we fail to enable communications here it's OK, + * since the DTR timer will cause a disconnected, which + * will retrigger communication in timer_intr() */ + if (ppp_comm_enable(card) == CMD_OK) { + wanpipe_set_state(card, WAN_CONNECTING); + init_ppp_tx_rx_buff(card); + } + + return 0; +} + +/*============================================================ + * ppp_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * PPP polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each ppp + * interface through a tq_schedule bottom half. + * + * trigger_ppp_poll() function is used to kick + * the ppp_poll routine. + */ +static void ppp_poll (netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area; + sdla_t *card; + u8 check_gateway=0; + ppp_flags_t *flags; + + if (!dev || (ppp_priv_area = dev->priv) == NULL) + return; + + card = ppp_priv_area->card; + flags = card->flags; + + /* Shutdown is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* if_open() function has triggered the polling routine + * to determine the configured IP addresses. Once the + * addresses are found, trigger the chdlc configuration */ + if (test_bit(0,&ppp_priv_area->config_ppp)){ + + ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); + ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && + card->u.p.ip_mode == WANOPT_PPP_HOST){ + + if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ + printk(KERN_INFO "\n%s: --- WARNING ---\n", + card->devname); + printk(KERN_INFO "%s: The local IP address is the same as the\n", + card->devname); + printk(KERN_INFO "%s: Point-to-Point IP address.\n", + card->devname); + printk(KERN_INFO "%s: --- WARNING ---\n\n", + card->devname); + }else{ + clear_bit(POLL_CRIT,&card->wandev.critical); + ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&ppp_priv_area->poll_delay_timer); + return; + } + } + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->imask |= PPP_INTR_TIMER; + ppp_priv_area->ip_error=0; + + clear_bit(0,&ppp_priv_area->config_ppp); + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* Dynamic interface implementation, as well as dynamic + * routing. */ + + switch (card->wandev.state) { + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the netowrk interface */ + + if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && + !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && + card->wandev.dev->flags & IFF_UP){ + + printk(KERN_INFO "%s: Interface %s down.\n", + card->devname,card->wandev.dev->name); + change_dev_flags(card->wandev.dev, + (card->wandev.dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&ppp_priv_area->interface_down); + }else{ + /* We need to check if the local IP address is + * zero. If it is, we shouldn't try to remove it. + * For some reason the kernel crashes badly if + * we try to remove the route twice */ + + if (card->wandev.dev->flags & IFF_UP && + get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && + card->u.p.ip_mode == WANOPT_PPP_PEER){ + + remove_route(card); + } + } + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && + test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && + !(card->wandev.dev->flags & IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s up.\n", + card->devname,card->wandev.dev->name); + + change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); + clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); + check_gateway=1; + } + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + test_bit(1,&Read_connection_info)) { + + process_route(card); + clear_bit(1,&Read_connection_info); + check_gateway=1; + } + + if (ppp_priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + clear_bit(POLL_CRIT,&card->wandev.critical); + return; +} + +/*============================================================ + * trigger_ppp_poll + * + * Description: + * Add a ppp_poll() task into a tq_scheduler bh handler + * for a specific interface. This will kick + * the ppp_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ + +static void trigger_ppp_poll (netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area; + if ((ppp_priv_area=dev->priv) != NULL){ + + sdla_t *card = ppp_priv_area->card; + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + + #ifdef LINUX_2_4 + schedule_task(&ppp_priv_area->poll_task); + #else + queue_task(&ppp_priv_area->poll_task, &tq_scheduler); + #endif + } + return; +} + +static void ppp_poll_delay (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + trigger_ppp_poll(dev); +} + +/*============================================================ + * detect_and_fix_tx_bug + * + * Description: + * On connect, if the board tx buffer ptr is not the same + * as the driver tx buffer ptr, we found a firmware bug. + * Report the bug to the above layer. To fix the + * error restart communications again. + * + * Usage: + * + */ + +static int detect_and_fix_tx_bug (sdla_t *card) +{ + if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ + NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); + return 1; + } + return 0; +} + /****** End *****************************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c --- v2.4.3/linux/drivers/net/wan/sdla_x25.c Tue Mar 6 19:44:36 2001 +++ linux/drivers/net/wan/sdla_x25.c Thu Apr 12 12:11:39 2001 @@ -1,16 +1,55 @@ /***************************************************************************** * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. * -* Author: Gene Kozin <genek@compuserve.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. * * 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. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.x porting +* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). +* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses +* a kernel timer (more efficient). +* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel +* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering +* for API to 4096+header_size. +* Jul 17, 2000 Nenad Corbic o 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. +* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. +* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. +* Disable idle timeout in X25 API. +* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. +* Maximum LCN number is 4095. +* Maximum number of X25 channels is 255. +* Apr 06, 2000 Nenad Corbic o Added SMP Support. +* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card +* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. +* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling +* routines. Bug Fix. +* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. +* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. +* Application must bring the link up +* before tx/rx, and bring the +* link down on close(). +* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup +* information. +* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API +* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. +* No Modem OOB message will be passed +* to the user. +* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support +* Dec 30, 1999 Nenad Corbic o Socket based X25API +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel +* Mar 15, 1998 Alan Cox o 2.1.x porting +* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * when they are disabled. * Nov 17, 1997 Farhan Thawar o Added IPX support @@ -38,21 +77,41 @@ * Jan 07, 1997 Gene Kozin Initial version. *****************************************************************************/ +/*====================================================== + * Includes + *=====================================================*/ +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/ctype.h> +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> +#include <asm/atomic.h> +#include <linux/delay.h> /* Experimental delay */ -#define _GNUC_ +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <asm/uaccess.h> +#else + #include <asm/segment.h> + #include <net/route.h> +#endif + +#include <linux/if.h> +#include <linux/if_arp.h> #include <linux/sdla_x25.h> /* X.25 firmware API definitions */ +#include <linux/if_wanpipe_common.h> +#include <linux/if_wanpipe.h> + + +/*====================================================== + * Defines & Macros + *=====================================================*/ -/****** Defines & Macros ****************************************************/ #define CMD_OK 0 /* normal firmware return code */ #define CMD_TIMEOUT 0xFF /* firmware command timed out */ @@ -64,27 +123,141 @@ #define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ +#define MAX_BH_BUFF 10 +#define M_BIT 0x01 + +//#define PRINT_DEBUG 1 +#ifdef PRINT_DEBUG +#define DBG_PRINTK(format, a...) printk(format, ## a) +#else +#define DBG_PRINTK(format, a...) +#endif + +#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 +#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 +#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 +#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 +#define TMR_INT_ENABLED_CMD_EXEC 0x10 +#define TMR_INT_ENABLED_UPDATE 0x20 +#define TMR_INT_ENABLED_UDP_PKT 0x40 + +#define MAX_X25_ADDR_SIZE 16 +#define MAX_X25_DATA_SIZE 129 +#define MAX_X25_FACL_SIZE 110 + +#define TRY_CMD_AGAIN 2 +#define DELAY_RESULT 1 +#define RETURN_RESULT 0 + +#define DCD(x) (x & 0x03 ? "HIGH" : "LOW") +#define CTS(x) (x & 0x05 ? "HIGH" : "LOW") + + +/* Driver will not write log messages about + * modem status if defined.*/ +#define MODEM_NOT_LOG 1 + +/*==================================================== + * For IPXWAN + *===================================================*/ -/* For IPXWAN */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) -/****** Data Structures *****************************************************/ -/* This is an extention of the 'struct net_device' we create for each network - * interface to keep the rest of X.25 channel-specific data. +/*==================================================== + * MEMORY DEBUGGING FUNCTION + *==================================================== + +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) + +==============================================================*/ + + + +/*=============================================== + * Data Structures + *===============================================*/ + + +/*======================================================== + * Name: x25_channel + * + * Purpose: To hold private informaton for each + * logical channel. + * + * Rationale: Per-channel debugging is possible if each + * channel has its own private area. + * + * Assumptions: + * + * Description: This is an extention of the 'netdevice_t' + * we create for each network interface to keep + * the rest of X.25 channel-specific data. + * + * Construct: Typedef */ typedef struct x25_channel { - /* This member must be first. */ - struct net_device *slave; /* WAN slave */ - + wanpipe_common_t common; /* common area for x25api and socket */ char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - unsigned lcn; /* logical channel number */ unsigned tx_pkt_size; unsigned short protocol; /* ethertype, 0 - multiplexed */ - char svc; /* 0 - permanent, 1 - switched */ - char state; /* channel state */ char drop_sequence; /* mark sequence for dropping */ unsigned long state_tick; /* time of the last state change */ unsigned idle_timeout; /* sec, before disconnecting */ @@ -94,63 +267,144 @@ char devtint; /* Weather we should dev_tint() */ struct sk_buff* rx_skb; /* receive socket buffer */ struct sk_buff* tx_skb; /* transmit socket buffer */ + + bh_data_t *bh_head; /* Circular buffer for x25api_bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; + sdla_t* card; /* -> owner */ + netdevice_t *dev; /* -> bound devce */ + int ch_idx; + unsigned char enable_IPX; + unsigned long network_number; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct net_device_stats ifstats; /* interface statistics */ +#else + struct enet_statistics ifstats; +#endif + unsigned short transmit_length; + unsigned short tx_offset; + char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; + + if_send_stat_t if_send_stat; + rx_intr_stat_t rx_intr_stat; + pipe_mgmt_stat_t pipe_mgmt_stat; + + unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_up_time; + } x25_channel_t; +/* FIXME Take this out */ + +#ifdef NEX_OLD_CALL_INFO typedef struct x25_call_info { - char dest[17]; /* ASCIIZ destination address */ - char src[17]; /* ASCIIZ source address */ - char nuser; /* number of user data bytes */ - unsigned char user[127]; /* user data */ - char nfacil; /* number of facilities */ + char dest[17]; PACKED;/* ASCIIZ destination address */ + char src[17]; PACKED;/* ASCIIZ source address */ + char nuser; PACKED;/* number of user data bytes */ + unsigned char user[127]; PACKED;/* user data */ + char nfacil; PACKED;/* number of facilities */ struct { - unsigned char code; - unsigned char parm; - } facil[64]; /* facilities */ + unsigned char code; PACKED; + unsigned char parm; PACKED; + } facil[64]; /* facilities */ +} x25_call_info_t; +#else +typedef struct x25_call_info +{ + char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ + char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ + unsigned char nuser PACKED; + unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ + unsigned char nfacil PACKED; + unsigned char facil[MAX_X25_FACL_SIZE] PACKED; + unsigned short lcn PACKED; } x25_call_info_t; +#endif + -/****** Function Prototypes *************************************************/ + +/*=============================================== + * Private Function Prototypes + *==============================================*/ -/* WAN link driver entry points. These are called by the WAN router module. */ + +/*================================================= + * WAN link driver entry points. These are + * called by the WAN router module. + */ static int update (wan_device_t* wandev); -static int new_if (wan_device_t* wandev, struct net_device* dev, +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); -static int del_if (wan_device_t* wandev, struct net_device* dev); +static int del_if (wan_device_t* wandev, netdevice_t* dev); +static void disable_comm (sdla_t* card); +static void disable_comm_shutdown(sdla_t *card); -/* WANPIPE-specific entry points */ + + +/*================================================= + * WANPIPE-specific entry points + */ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); +static void x25api_bh (netdevice_t *); +static int x25api_bh_cleanup (netdevice_t *); +static int bh_enqueue (netdevice_t *, struct sk_buff *); + -/* Network device interface */ -static int if_init (struct net_device* dev); -static int if_open (struct net_device* dev); -static int if_close (struct net_device* dev); -static int if_header (struct sk_buff* skb, struct net_device* dev, +/*================================================= + * Network device interface + */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len); static int if_rebuild_hdr (struct sk_buff* skb); -static int if_send (struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats * if_stats (struct net_device* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats *if_stats (netdevice_t* dev); -/* Interrupt handlers */ -static void wpx_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void tx_intr (sdla_t* card); -static void status_intr (sdla_t* card); -static void event_intr (sdla_t* card); -static void spur_intr (sdla_t* card); +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +/*================================================= + * Interrupt handlers + */ +static void wpx_isr (sdla_t *); +static void rx_intr (sdla_t *); +static void tx_intr (sdla_t *); +static void status_intr (sdla_t *); +static void event_intr (sdla_t *); +static void spur_intr (sdla_t *); +static void timer_intr (sdla_t *); -/* Background polling routines */ +static int tx_intr_send(sdla_t *, netdevice_t *); +static netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *); + +/*================================================= + * Background polling routines + */ static void wpx_poll (sdla_t* card); static void poll_disconnected (sdla_t* card); static void poll_connecting (sdla_t* card); static void poll_active (sdla_t* card); +static void trigger_x25_poll(sdla_t *card); +static void x25_timer_routine(unsigned long data); + + -/* X.25 firmware interface functions */ +/*================================================= + * X.25 firmware interface functions + */ static int x25_get_version (sdla_t* card, char* str); static int x25_configure (sdla_t* card, TX25Config* conf); +static int hdlc_configure (sdla_t* card, TX25Config* conf); +static int set_hdlc_level (sdla_t* card); static int x25_get_err_stats (sdla_t* card); static int x25_get_stats (sdla_t* card); static int x25_set_intr_mode (sdla_t* card, int mode); @@ -166,62 +420,136 @@ static int x25_fetch_events (sdla_t* card); static int x25_error (sdla_t* card, int err, int cmd, int lcn); -/* X.25 asynchronous event handlers */ +/*================================================= + * X.25 asynchronous event handlers + */ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -/* Miscellaneous functions */ + +/*================================================= + * Miscellaneous functions + */ static int connect (sdla_t* card); static int disconnect (sdla_t* card); -static struct net_device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); -static int chan_connect (struct net_device* dev); -static int chan_disc (struct net_device* dev); -static void set_chan_state (struct net_device* dev, int state); -static int chan_send (struct net_device* dev, struct sk_buff* skb); +static netdevice_t* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); +static int chan_connect (netdevice_t* dev); +static int chan_disc (netdevice_t* dev); +static void set_chan_state (netdevice_t* dev, int state); +static int chan_send (netdevice_t* , void* , unsigned, unsigned char); static unsigned char bps_to_speed_code (unsigned long bps); static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char* str, int len); -static void parse_call_info (unsigned char* str, x25_call_info_t* info); +static unsigned int hex_to_uint (unsigned char*, int); +static void parse_call_info (unsigned char*, x25_call_info_t*); +static netdevice_t * find_channel(sdla_t *, unsigned); +static void bind_lcn_to_dev (sdla_t *, netdevice_t *,unsigned); +static void setup_for_delayed_transmit (netdevice_t*, void*, unsigned); + + +/*================================================= + * X25 API Functions + */ +static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **); +static void timer_intr_exec(sdla_t *, unsigned char); +static int execute_delayed_cmd (sdla_t*, netdevice_t *, mbox_cmd_t *,char); +static int api_incoming_call (sdla_t*, TX25Mbox *, int); +static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); +static void send_delayed_cmd_result(sdla_t *, netdevice_t *dev, TX25Mbox*); +static int clear_confirm_event (sdla_t *, TX25Mbox*); +static void send_oob_msg (sdla_t *, netdevice_t *, TX25Mbox *); +static int timer_intr_cmd_exec(sdla_t *card); +static void api_oob_event (sdla_t *card,TX25Mbox *mbox); +static int check_bad_command (sdla_t *, netdevice_t *); +static int channel_disconnect (sdla_t*, netdevice_t *); +static void hdlc_link_down (sdla_t*); + +/*================================================= + * XPIPEMON Functions + */ +static int process_udp_mgmt_pkt(sdla_t *); +static int udp_pkt_type( struct sk_buff *, sdla_t*); +static int reply_udp( unsigned char *, unsigned int); +static void init_x25_channel_struct( x25_channel_t *); +static void init_global_statistics( sdla_t *); +static int store_udp_mgmt_pkt(int, char, sdla_t*, netdevice_t *, struct sk_buff *, int); +static unsigned short calc_checksum (char *, int); -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); + + +/*================================================= + * IPX functions + */ +static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); +static int handle_IPXWAN(unsigned char *, char *, unsigned char , + unsigned long , unsigned short ); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ +static void S508_S514_lock(sdla_t *, unsigned long *); +static void S508_S514_unlock(sdla_t *, unsigned long *); -/****** Public Functions ****************************************************/ -/*============================================================================ - * X.25 Protocol Initialization routine. +/*================================================= + * Global Variables + *=================================================*/ + + + +/*================================================= + * Public Functions + *=================================================*/ + + + + +/*=================================================================== + * wpx_init: X.25 Protocol Initialization routine. + * + * Purpose: To initialize the protocol/firmware. + * + * Rationale: This function is called by setup() function, in + * sdlamain.c, to dynamically setup the x25 protocol. + * This is the first protocol specific function, which + * executes once on startup. + * + * Description: This procedure initializes the x25 firmware and + * sets up the mailbox, transmit and receive buffer + * pointers. It also initializes all debugging structures + * and sets up the X25 environment. * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. + * Sets up hardware options defined by user in [wanpipe#] + * section of wanpipe#.conf configuration file. * - * Return: 0 o.k. - * < 0 failure. + * At this point adapter is completely initialized + * and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the + * adapter data space. + * + * Called by: setup() function in sdlamain.c + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 o.k. + * < 0 failure. */ + int wpx_init (sdla_t* card, wandev_conf_t* conf) { - union - { + union{ char str[80]; TX25Config cfg; } u; /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25) - { + if (conf->config_id != WANCONFIG_X25){ printk(KERN_INFO "%s: invalid configuration ID %u!\n", card->devname, conf->config_id) ; @@ -233,23 +561,43 @@ card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); + /* Initialize for S514 Card */ + if(card->hw.type == SDLA_S514) { + card->mbox += X25_MB_VECTOR; + card->flags += X25_MB_VECTOR; + card->rxmb += X25_MB_VECTOR; + } + + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work * around this, we execute the first command twice. */ if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) - return -EIO - ; - printk(KERN_INFO "%s: running X.25 firmware v%s\n", - card->devname, u.str) - ; + return -EIO; + + + /* X25 firmware can run ether in X25 or LAPB HDLC mode. + * Check the user defined option and configure accordingly */ + if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ + if (set_hdlc_level(card) != CMD_OK){ + return -EIO; + }else{ + printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", + card->devname, u.str); + } + card->u.x.LAPB_hdlc = 1; + }else{ + printk(KERN_INFO "%s: running X.25 firmware v%s\n", + card->devname, u.str); + card->u.x.LAPB_hdlc = 0; + } /* Configure adapter. Here we set resonable defaults, then parse * device configuration structure and set configuration options. * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so and don't - * want it to fail either. + * necessary) since we can't rely on the adapter to do so. */ memset(&u.cfg, 0, sizeof(u.cfg)); u.cfg.t1 = 3; @@ -258,7 +606,7 @@ u.cfg.hdlcWindow = 7; u.cfg.pktWindow = 2; u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x00B0; /* disable D-bit pragmatics */ + u.cfg.options = 0x0090; /* disable D-bit pragmatics */ u.cfg.ccittCompat = 1988; u.cfg.t10t20 = 30; u.cfg.t11t21 = 30; @@ -271,71 +619,120 @@ u.cfg.r13r23 = 5; u.cfg.responseOpt = 1; /* RR's after every packet */ + if (card->u.x.LAPB_hdlc){ + u.cfg.hdlcMTU = 1027; + } + + if (conf->u.x25.x25_conf_opt){ + u.cfg.options = conf->u.x25.x25_conf_opt; + } + if (conf->clocking != WANOPT_EXTERNAL) - u.cfg.baudRate = bps_to_speed_code(conf->bps) - ; - if (conf->station != WANOPT_DTE) - { + u.cfg.baudRate = bps_to_speed_code(conf->bps); + + if (conf->station != WANOPT_DTE){ u.cfg.station = 0; /* DCE mode */ } - if (conf->interface != WANOPT_RS232 ) { + + if (conf->interface != WANOPT_RS232 ){ u.cfg.hdlcOptions |= 0x80; /* V35 mode */ } + /* adjust MTU */ if (!conf->mtu || (conf->mtu >= 1024)) - card->wandev.mtu = 1024 - ; + card->wandev.mtu = 1024; else if (conf->mtu >= 512) - card->wandev.mtu = 512 - ; + card->wandev.mtu = 512; else if (conf->mtu >= 256) - card->wandev.mtu = 256 - ; + card->wandev.mtu = 256; else if (conf->mtu >= 128) - card->wandev.mtu = 128 - ; - else card->wandev.mtu = 64; + card->wandev.mtu = 128; + else + card->wandev.mtu = 64; + u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; - if (conf->u.x25.hi_pvc) - { - card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); + if (conf->u.x25.hi_pvc){ + card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, MAX_LCN_NUM); card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); } - if (conf->u.x25.hi_svc) - { - card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); + + if (conf->u.x25.hi_svc){ + card->u.x.hi_svc = min(conf->u.x25.hi_svc, MAX_LCN_NUM); card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); } - u.cfg.loPVC = card->u.x.lo_pvc; - u.cfg.hiPVC = card->u.x.hi_pvc; + + /* Figure out the total number of channels to configure */ + card->u.x.num_of_ch = 0; + if (card->u.x.hi_svc != 0){ + card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; + } + if (card->u.x.hi_pvc != 0){ + card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; + } + + if (card->u.x.num_of_ch == 0){ + printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" + "%s: Please set the Lowest/Highest PVC/SVC values !\n", + card->devname,card->devname); + return -ECHRNG; + } + + u.cfg.loPVC = card->u.x.lo_pvc; + u.cfg.hiPVC = card->u.x.hi_pvc; u.cfg.loTwoWaySVC = card->u.x.lo_svc; u.cfg.hiTwoWaySVC = card->u.x.hi_svc; if (conf->u.x25.hdlc_window) - u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7) - ; + u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7); if (conf->u.x25.pkt_window) - u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7) - ; + u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7); + if (conf->u.x25.t1) - u.cfg.t1 = min(conf->u.x25.t1, 30) - ; - u.cfg.t2 = min(conf->u.x25.t2, 29); - u.cfg.t4 = min(conf->u.x25.t4, 240); + u.cfg.t1 = min(conf->u.x25.t1, 30); + if (conf->u.x25.t2) + u.cfg.t2 = min(conf->u.x25.t2, 29); + if (conf->u.x25.t4) + u.cfg.t4 = min(conf->u.x25.t4, 240); if (conf->u.x25.n2) - u.cfg.n2 = min(conf->u.x25.n2, 30) - ; + u.cfg.n2 = min(conf->u.x25.n2, 30); + + if (conf->u.x25.t10_t20) + u.cfg.t10t20 = min(conf->u.x25.t10_t20,255); + if (conf->u.x25.t11_t21) + u.cfg.t11t21 = min(conf->u.x25.t11_t21,255); + if (conf->u.x25.t12_t22) + u.cfg.t12t22 = min(conf->u.x25.t12_t22,255); + if (conf->u.x25.t13_t23) + u.cfg.t13t23 = min(conf->u.x25.t13_t23,255); + if (conf->u.x25.t16_t26) + u.cfg.t16t26 = min(conf->u.x25.t16_t26, 255); + if (conf->u.x25.t28) + u.cfg.t28 = min(conf->u.x25.t28, 255); + + if (conf->u.x25.r10_r20) + u.cfg.r10r20 = min(conf->u.x25.r10_r20,250); + if (conf->u.x25.r12_r22) + u.cfg.r12r22 = min(conf->u.x25.r12_r22,250); + if (conf->u.x25.r13_r23) + u.cfg.r13r23 = min(conf->u.x25.r13_r23,250); + + if (conf->u.x25.ccitt_compat) - u.cfg.ccittCompat = conf->u.x25.ccitt_compat - ; + u.cfg.ccittCompat = conf->u.x25.ccitt_compat; /* initialize adapter */ - if ((x25_configure(card, &u.cfg) != CMD_OK) || - (x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ + if (card->u.x.LAPB_hdlc){ + if (hdlc_configure(card, &u.cfg) != CMD_OK) + return -EIO; + }else{ + if (x25_configure(card, &u.cfg) != CMD_OK) + return -EIO; + } + + if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ - return -EIO - ; + return -EIO; /* Initialize protocol-specific fields of adapter data space */ card->wandev.bps = conf->bps; @@ -343,202 +740,386 @@ card->wandev.clocking = conf->clocking; card->wandev.station = conf->station; card->isr = &wpx_isr; - card->poll = &wpx_poll; + card->poll = NULL; //&wpx_poll; + card->disable_comm = &disable_comm; card->exec = &wpx_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; + + /* WARNING: This function cannot exit with an error + * after the change of state */ card->wandev.state = WAN_DISCONNECTED; + card->wandev.enable_tx_int = 0; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; + card->u.x.tx_dev = NULL; + card->u.x.no_dev = 0; + + + /* Configure for S514 PCI Card */ + if (card->hw.type == SDLA_S514) { + card->u.x.hdlc_buf_status = + (volatile unsigned char *) + (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); + }else{ + card->u.x.hdlc_buf_status = + (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); + } + + card->u.x.poll_device=NULL; + card->wandev.udp_port = conf->udp_port; + + /* Enable or disable call setup logging */ + if (conf->u.x25.logging == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling Call Logging.\n", + card->devname); + card->u.x.logging = 1; + }else{ + card->u.x.logging = 0; + } + + /* Enable or disable modem status reporting */ + if (conf->u.x25.oob_on_modem == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", + card->devname); + card->u.x.oob_on_modem = 1; + }else{ + card->u.x.oob_on_modem = 0; + } + + init_global_statistics(card); + + #ifndef LINUX_2_4 + card->u.x.x25_poll_task.next = NULL; + #endif + card->u.x.x25_poll_task.sync=0; + card->u.x.x25_poll_task.routine = (void*)(void*)wpx_poll; + card->u.x.x25_poll_task.data = card; + + init_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.data = (unsigned long)card; + card->u.x.x25_timer.function = x25_timer_routine; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; return 0; } -/******* WAN Device Driver Entry Points *************************************/ +/*========================================================= + * WAN Device Driver Entry Points + *========================================================*/ -/*============================================================================ - * Update device status & statistics. +/*============================================================ + * Name: update(), Update device status & statistics. + * + * Purpose: To provide debugging and statitical + * information to the /proc file system. + * /proc/net/wanrouter/wanpipe# + * + * Rationale: The /proc file system is used to collect + * information about the kernel and drivers. + * Using the /proc file system the user + * can see exactly what the sangoma drivers are + * doing. And in what state they are in. + * + * Description: Collect all driver statistical information + * and pass it to the top laywer. + * + * Since we have to execute a debugging command, + * to obtain firmware statitics, we trigger a + * UPDATE function within the timer interrtup. + * We wait until the timer update is complete. + * Once complete return the appropriate return + * code to indicate that the update was successful. + * + * Called by: device_stat() in wanmain.c + * + * Assumptions: + * + * Warnings: This function will degrade the performance + * of the router, since it uses the mailbox. + * + * Return: 0 OK + * <0 Failed (or busy). */ + static int update (wan_device_t* wandev) { - sdla_t* card; + volatile sdla_t* card; + TX25Status* status; + unsigned long timeout; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void*)&wandev->critical)) + + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) return -EAGAIN; + + if (!wandev->dev) + return -ENODEV; + card = wandev->private; + status = card->flags; - x25_get_err_stats(card); - x25_get_stats(card); - wandev->critical = 0; + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; + status->imask |= INTR_ON_TIMER; + timeout = jiffies; + + for (;;){ + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ + break; + } + if ((jiffies-timeout) > 1*HZ){ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } return 0; } -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. + +/*=================================================================== + * Name: new_if + * + * Purpose: To allocate and initialize resources for a + * new logical channel. + * + * Rationale: A new channel can be added dynamically via + * ioctl call. + * + * Description: Allocate a private channel structure, x25_channel_t. + * Parse the user interface options from wanpipe#.conf + * configuration file. + * Bind the private are into the network device private + * area pointer (dev->priv). + * Prepare the network device structure for registration. + * + * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() + * (wanmain.c) + * + * Assumptions: None * - * Return: 0 o.k. - * < 0 failure (channel will not be created) + * Warnings: None + * + * Return: 0 Ok + * <0 Failed (channel will not be created) */ -static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; x25_channel_t* chan; int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ printk(KERN_INFO "%s: invalid interface name!\n", - card->devname) - ; + card->devname); return -EINVAL; } + if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { + printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", + card->devname); + printk(KERN_INFO + "%s: Maximum number of network interfaces must be one !\n", + card->devname); + return -EEXIST; + } + /* allocate and initialize private data */ - chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL); - if (chan == NULL) - return -ENOMEM - ; + chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); + if (chan == NULL){ + return -ENOMEM; + } + memset(chan, 0, sizeof(x25_channel_t)); + + /* Bug Fix: Seg Err on PVC startup + * It must be here since bind_lcn_to_dev expects + * it bellow */ + dev->priv = chan; + strcpy(chan->name, conf->name); chan->card = card; - chan->protocol = ETH_P_IP; + chan->dev = dev; + chan->common.sk = NULL; + chan->common.func = NULL; + chan->common.rw_bind = 0; chan->tx_skb = chan->rx_skb = NULL; /* verify media address */ - if (conf->addr[0] == '@') /* SVC */ - { - chan->svc = 1; + if (conf->addr[0] == '@'){ /* SVC */ + chan->common.svc = 1; strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); /* Set channel timeouts (default if not specified) */ - chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90; - chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; - } - else if (is_digit(conf->addr[0])) /* PVC */ - { + chan->idle_timeout = (conf->idle_timeout) ? + conf->idle_timeout : 90; + chan->hold_timeout = (conf->hold_timeout) ? + conf->hold_timeout : 10; + + }else if (is_digit(conf->addr[0])){ /* PVC */ int lcn = dec_to_uint(conf->addr, 0); - if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)) - { - chan->lcn = lcn; - } - else - { + if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ + bind_lcn_to_dev (card, dev, lcn); + }else{ printk(KERN_ERR "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name) - ; + wandev->name, lcn, chan->name); err = -EINVAL; } - } - else - { + }else{ printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", + wandev->name, chan->name); + chan->common.usedby = WANPIPE; + chan->protocol = htons(ETH_P_IP); + + }else if(strcmp(conf->usedby, "API") == 0){ + chan->common.usedby = API; + printk(KERN_INFO "%s: Running in API mode %s\n", + wandev->name, chan->name); + chan->protocol = htons(X25_PROT); + } + + + if (err){ kfree(chan); + dev->priv = NULL; return err; } + + chan->enable_IPX = conf->enable_IPX; + + if (chan->enable_IPX) + chan->protocol = htons(ETH_P_IPX); + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; /* prepare network device data space for registration */ - strcpy(dev->name, chan->name); + #ifdef LINUX_2_4 + strcpy(dev->name,chan->name); + #else + dev->name = (char *)kmalloc(strlen(chan->name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", chan->name); + #endif dev->init = &if_init; - dev->priv = chan; + + init_x25_channel_struct(chan); + return 0; } -/*============================================================================ - * Delete logical channel. +/*=================================================================== + * Name: del_if(), Remove a logical channel. + * + * Purpose: To dynamically remove a logical channel. + * + * Rationale: Each logical channel should be dynamically + * removable. This functin is called by an + * IOCTL_IFDEL ioctl call or shutdown(). + * + * Description: Do nothing. + * + * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c + * shutdown() from sdlamain.c + * + * Assumptions: + * + * Warnings: + * + * Return: 0 Ok. Void function. */ -static int del_if (wan_device_t* wandev, struct net_device* dev) + +//FIXME Del IF Should be taken out now. + +static int del_if (wan_device_t* wandev, netdevice_t* dev) { - if (dev->priv) - { - kfree(dev->priv); - dev->priv = NULL; - } return 0; } -/****** WANPIPE-specific entry points ***************************************/ -/*============================================================================ - * Execute adapter interface command. - */ +/*============================================================ + * Name: wpx_exec + * + * Description: Execute adapter interface command. + * This option is currently dissabled. + *===========================================================*/ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) { - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - TX25Cmd cmd; - - if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - - /* execute command */ + return 0; +} - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return-EFAULT; - } - if (sdla_exec(mbox)) - err = mbox->cmd.result - ; - else return -EIO; - } - while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); +/*============================================================ + * Name: disable_comm + * + * Description: Disable communications during shutdown. + * Dont check return code because there is + * nothing we can do about it. + * + * Warning: Dev and private areas are gone at this point. + *===========================================================*/ - /* return result */ - if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) - return -EFAULT; - len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - return 0; +static void disable_comm(sdla_t* card) +{ + disable_comm_shutdown(card); + del_timer(&card->u.x.x25_timer); + return; } -/****** Network Device Interface ********************************************/ -/*============================================================================ - * Initialize Linux network interface. +/*============================================================ + * Network Device Interface + *===========================================================*/ + +/*=================================================================== + * Name: if_init(), Netowrk Interface Initialization * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. + * Purpose: To initialize a network interface device structure. + * + * Rationale: During network interface startup, the if_init + * is called by the kernel to initialize the + * netowrk device structure. Thus a driver + * can customze a network device. + * + * Description: Initialize the netowrk device call back + * routines. This is where we tell the kernel + * which function to use when it wants to send + * via our interface. + * Furthermore, we initialize the device flags, + * MTU and physical address of the board. + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->init()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok : Void function. */ -static int if_init (struct net_device* dev) +static int if_init (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; wan_device_t* wandev = &card->wandev; + #ifdef LINUX_2_0 + int i; + #endif /* Initialize device driver entry points */ dev->open = &if_open; @@ -548,127 +1129,270 @@ dev->hard_start_xmit = &if_send; dev->get_stats = &if_stats; + #ifdef LINUX_2_4 + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + #endif + /* Initialize media-specific parameters */ - dev->type = 30; /* ARP h/w type */ - dev->mtu = X25_CHAN_MTU; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + dev->type = ARPHRD_PPP; /* ARP h/w type */ + #else + dev->family = AF_INET; /* address family */ + dev->type = ARPHRD_PPP; /* no x25 type */ + #endif + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + if (chan->common.usedby == API){ + dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); + }else{ + dev->mtu = card->wandev.mtu; + } + dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ dev->addr_len = 2; /* hardware address length */ - if (!chan->svc) - *(unsigned short*)dev->dev_addr = htons(chan->lcn); - + + if (!chan->common.svc){ + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); + } + /* Initialize hardware parameters (just for reference) */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_end + wandev->msize - 1; + dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; + dev->tx_queue_len = 100; /* Initialize socket buffers */ - - dev_init_buffers(dev); + #if defined(LINUX_2_1) || defined(LINUX_2_4) + dev_init_buffers(dev); + #else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); + #endif + + /* FIXME Why are we doing this */ set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection + +/*=================================================================== + * Name: if_open(), Open/Bring up the Netowrk Interface + * + * Purpose: To bring up a network interface. + * + * Rationale: + * + * Description: Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection * - * Return 0 if O.k. or errno. + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->open()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failur: Interface will not come up. */ -static int if_open (struct net_device* dev) + +static int if_open (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; + struct timeval tv; + unsigned long smp_flags; + + if (is_dev_running(dev)) + return -EBUSY; - if (dev->start) - return -EBUSY; /* only one open is allowed */ + chan->tq_working = 0; + + /* Initialize the task queue */ + #ifndef LINUX_2_4 + chan->common.wanpipe_task.next = NULL; + #endif + chan->common.wanpipe_task.sync = 0; + chan->common.wanpipe_task.routine = (void *)(void *)x25api_bh; + chan->common.wanpipe_task.data = dev; + + /* Allocate and initialize BH circular buffer */ + /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ + chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); + + if (chan->bh_head == NULL){ + printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", + card->devname); + + return -ENOBUFS; + } + memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); + atomic_set(&chan->bh_buff_used, 0); + + /* Increment the number of interfaces */ + ++card->u.x.no_dev; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; + wanpipe_open(card); + /* LAPB protocol only uses one interface, thus + * start the protocol after it comes up. */ + if (card->u.x.LAPB_hdlc){ + if (card->open_cnt == 1){ + TX25Status* status = card->flags; + S508_S514_lock(card, &smp_flags); + x25_set_intr_mode(card, INTR_ON_TIMER); + status->imask &= ~INTR_ON_TIMER; + S508_S514_unlock(card, &smp_flags); + } + }else{ + /* X25 can have multiple interfaces thus, start the + * protocol once all interfaces are up */ + + //FIXME: There is a bug here. If interface is + //brought down and up, it will try to enable comm. + if (card->open_cnt == card->u.x.num_of_ch){ + + S508_S514_lock(card, &smp_flags); + connect(card); + S508_S514_unlock(card, &smp_flags); + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+HZ; + add_timer(&card->u.x.x25_timer); + } + } + /* Device is not up untill the we are in connected state */ + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; + + #ifdef LINUX_2_4 + netif_start_queue(dev); + #else dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - wanpipe_open(card); + #endif - /* If this is the first open, initiate physical connection */ - if (card->open_cnt == 1) - connect(card); - card->wandev.critical = 0; return 0; } -/*============================================================================ - * Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. +/*=================================================================== + * Name: if_close(), Close/Bring down the Netowrk Interface + * + * Purpose: To bring down a network interface. + * + * Rationale: + * + * Description: Close network interface. + * o decrement use module use count + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->close()) + * ifconfig <name> down: will trigger the kernel + * which will call this function. + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failure: Interface will not exit properly. */ -static int if_close (struct net_device* dev) +static int if_close (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - return -EAGAIN; - - dev->start = 0; - if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) + unsigned long smp_flags; + + stop_net_queue(dev); + #ifndef LINUX_2_4 + dev->start=0; + #endif + + if ((chan->common.state == WAN_CONNECTED) || + (chan->common.state == WAN_CONNECTING)){ + S508_S514_lock(card, &smp_flags); chan_disc(dev); - + S508_S514_unlock(card, &smp_flags); + } + wanpipe_close(card); + S508_S514_lock(card, &smp_flags); + if (chan->bh_head){ + int i; + struct sk_buff *skb; + + for (i=0; i<(MAX_BH_BUFF+1); i++){ + skb = ((bh_data_t *)&chan->bh_head[i])->skb; + if (skb != NULL){ + wan_dev_kfree_skb(skb, FREE_READ); + } + } + kfree(chan->bh_head); + chan->bh_head=NULL; + } + S508_S514_unlock(card, &smp_flags); + /* If this is the last close, disconnect physical link */ - if (!card->open_cnt) + if (!card->open_cnt){ + S508_S514_lock(card, &smp_flags); disconnect(card); - - card->wandev.critical = 0; + x25_set_intr_mode(card, 0); + S508_S514_unlock(card, &smp_flags); + } + + /* Decrement the number of interfaces */ + --card->u.x.no_dev; return 0; } -/*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. +/*====================================================================== + * Build media header. + * o encapsulate packet according to encapsulation type. * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. + * The trick here is to put packet type (Ethertype) into 'protocol' + * field of the socket buffer, so that we don't forget it. + * If encapsulation fails, set skb->protocol to 0 and discard + * packet later. * - * Return: media header length. - */ -static int if_header (struct sk_buff* skb, struct net_device* dev, + * Return: media header length. + *======================================================================*/ + +static int if_header (struct sk_buff* skb, netdevice_t* dev, unsigned short type, void* daddr, void* saddr, unsigned len) { x25_channel_t* chan = dev->priv; int hdr_len = dev->hard_header_len; - - skb->protocol = type; - if (!chan->protocol) - { - hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { + + skb->protocol = htons(type); + if (!chan->protocol){ + hdr_len = wanrouter_encapsulate(skb, dev, type); + if (hdr_len < 0){ hdr_len = 0; - skb->protocol = 0; + skb->protocol = htons(0); } } return hdr_len; } -/*============================================================================ - * Re-build media header. +/*=============================================================== + * Re-build media header. * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ - + * Return: 1 physical address resolved. + * 0 physical address not resolved + *==============================================================*/ + static int if_rebuild_hdr (struct sk_buff* skb) { - struct net_device *dev=skb->dev; + netdevice_t *dev = skb->dev; x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -677,185 +1401,294 @@ return 1; } + +#ifdef LINUX_2_4 /*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_send_stat.if_send_tbusy_timeout; + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); + netif_wake_queue (dev); +} +#endif + + +/*========================================================================= + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer * - * Return: 0 complete (socket buffer must be freed) + * Return: 0 complete (socket buffer must be freed) * non-0 packet may be re-transmitted (tbusy must be set) * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + * + *========================================================================*/ -static int if_send (struct sk_buff* skb, struct net_device* dev) +static int if_send (struct sk_buff* skb, netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - struct net_device *dev2; TX25Status* status = card->flags; - unsigned long host_cpu_flags; + int udp_type; + unsigned long smp_flags=0; - if (dev->tbusy) - { - ++chan->ifstats.rx_dropped; - if ((jiffies - chan->tick_counter) < (5*HZ)) - { - return dev->tbusy; + ++chan->if_send_stat.if_send_entry; + + #ifdef LINUX_2_4 + netif_stop_queue(dev); + #endif + + /* No need to check frame length, since socket code + * will perform the check for us */ + + #ifndef LINUX_2_4 + if (dev->tbusy){ + netdevice_t *dev2; + + ++chan->if_send_stat.if_send_tbusy; + if ((jiffies - chan->tick_counter) < (5*HZ)){ + return 1; } printk(KERN_INFO "%s: Transmit time out %s!\n", - card->devname, dev->name); + card->devname, dev->name); + + for( dev2 = card->wandev.dev; dev2; + dev2 = *((netdevice_t**)dev2->priv)){ - dev2 = card->wandev.dev; - while (dev2) { - x25_channel_t *chan2 = dev2->priv; dev2->tbusy = 0; - dev2 = chan2->slave; } + ++chan->if_send_stat.if_send_tbusy_timeout; } + #endif + chan->tick_counter = jiffies; + + /* Critical region starts here */ + S508_S514_lock(card, &smp_flags); + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); + goto if_send_crit_exit; + } + + udp_type = udp_pkt_type(skb, card); - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; + if(udp_type != UDP_INVALID_TYPE) { - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "Hit critical in if_send()!\n"); - if (card->wandev.critical == CRITICAL_IN_ISR) - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - - return dev->tbusy; - } - dev_kfree_skb(skb); - - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, + chan->common.lcn)) { - return dev->tbusy; + status->imask |= INTR_ON_TIMER; + if (udp_type == UDP_XPIPE_TYPE){ + chan->if_send_stat.if_send_PIPE_request++; + } + } + start_net_queue(dev); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 0; } - /* Below is only until we have per-channel IPX going.... */ - if(!(chan->svc)) - chan->protocol = skb->protocol; + if (chan->transmit_length){ + //FIXME: This check doesn't make sense any more + if (chan->common.state != WAN_CONNECTED){ + chan->transmit_length=0; + atomic_set(&chan->common.driver_busy,0); + }else{ + stop_net_queue(dev); + ++card->u.x.tx_interrupts_pending; + status->imask |= INTR_ON_TX_FRAME; + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 1; + } + } - if (card->wandev.state != WAN_CONNECTED) + if (card->wandev.state != WAN_CONNECTED){ ++chan->ifstats.tx_dropped; - - /* Below is only until we have per-channel IPX going.... */ - else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) - { + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_wan_disconnected; + + }else if ( chan->protocol && (chan->protocol != skb->protocol)){ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - card->devname, skb->protocol, dev->name); + chan->name, htons(skb->protocol), dev->name); + + printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); ++chan->ifstats.tx_errors; - } - else switch (chan->state) - { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_protocol_error; + + }else switch (chan->common.state){ + case WAN_DISCONNECTED: /* Try to establish connection. If succeded, then start * transmission, else drop a packet. */ - if (chan_connect(dev) != 0) - { + if (chan->common.usedby == API){ ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; break; + }else{ + if (chan_connect(dev) != 0){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } } /* fall through */ case WAN_CONNECTED: - if( skb->protocol == ETH_P_IPX ) - { - if(card->wandev.enable_IPX) - { + if( skb->protocol == htons(ETH_P_IPX)) { + if(chan->enable_IPX) { switch_net_numbers( skb->data, - card->wandev.network_number, 0); - } - else - { + chan->network_number, 0); + } else { ++card->wandev.stats.tx_dropped; ++chan->ifstats.tx_dropped; - goto tx_done; + ++chan->if_send_stat.if_send_protocol_error; + goto if_send_crit_exit; } } - dev->trans_start = jiffies; - if(chan_send(dev, skb)) - { - dev->tbusy = 1; - status->imask |= 0x2; - } + /* We never drop here, if cannot send than, copy + * a packet into a transmit buffer + */ + chan_send(dev, skb->data, skb->len, 0); break; default: ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; + break; } -tx_done: - if (!dev->tbusy) - dev_kfree_skb(skb); - - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return dev->tbusy; + + +if_send_crit_exit: + + wan_dev_kfree_skb(skb, FREE_WRITE); + + start_net_queue(dev); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 0; } /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats - */ - -static struct net_device_stats* if_stats (struct net_device* dev) + * Setup so that a frame can be transmitted on the occurence of a transmit + * interrupt. + *===========================================================================*/ + +static void setup_for_delayed_transmit (netdevice_t* dev, void* buf, + unsigned len) { - x25_channel_t* chan = dev->priv; - if(chan==NULL) + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + TX25Status* status = card->flags; + + ++chan->if_send_stat.if_send_adptr_bfrs_full; + + if(chan->transmit_length) { + printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", + card->devname); + return; + } + + if (chan->common.usedby == API){ + if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + printk(KERN_INFO "%s: Length is too big for delayed transmit\n", + card->devname); + return; + } + }else{ + if (len > X25_MAX_DATA) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + printk(KERN_INFO "%s: Length is too big for delayed transmit\n", + card->devname); + return; + } + } + + chan->transmit_length = len; + atomic_set(&chan->common.driver_busy,1); + memcpy(chan->transmit_buffer, buf, len); + + ++chan->if_send_stat.if_send_tx_int_enabled; + + /* Enable Transmit Interrupt */ + ++card->u.x.tx_interrupts_pending; + status->imask |= INTR_ON_TX_FRAME; +} + + +/*=============================================================== + * net_device_stats + * + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + * + *==============================================================*/ +static struct net_device_stats *if_stats (netdevice_t* dev) +{ + x25_channel_t *chan = dev->priv; + + if(chan == NULL) return NULL; + return &chan->ifstats; } -/****** Interrupt Handlers **************************************************/ -/*============================================================================ +/* + * Interrupt Handlers + */ + +/* * X.25 Interrupt Service Routine. */ - + static void wpx_isr (sdla_t* card) { TX25Status* status = card->flags; - struct net_device *dev; - unsigned long host_cpu_flags; card->in_isr = 1; - card->buff_int_mode_unbusy = 0; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ + card->in_isr=0; + status->iflags = 0; + return; + } + + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); + printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", + card->devname, card->wandev.critical, status->iflags); card->in_isr = 0; + status->iflags = 0; return; } @@ -863,92 +1696,62 @@ * If the if_send routine is called with this flag set it will set * the enable transmit flag to 1. (for a delayed interrupt) */ - card->wandev.critical = CRITICAL_IN_ISR; + switch (status->iflags){ - switch (status->iflags) - { - case 0x01: /* receive interrupt */ + case RX_INTR_PENDING: /* receive interrupt */ rx_intr(card); break; - case 0x02: /* transmit interrupt */ + case TX_INTR_PENDING: /* transmit interrupt */ tx_intr(card); - card->buff_int_mode_unbusy = 1; - status->imask &= ~0x2; break; - case 0x04: /* modem status interrupt */ + case MODEM_INTR_PENDING: /* modem status interrupt */ status_intr(card); break; - case 0x10: /* network event interrupt */ + case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ event_intr(card); break; + case TIMER_INTR_PENDING: + timer_intr(card); + break; + default: /* unwanted interrupt */ spur_intr(card); } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if( card->wandev.enable_tx_int) - { - card->wandev.enable_tx_int = 0; - status->imask |= 0x2; - } - save_flags(host_cpu_flags); - cli(); + card->in_isr = 0; status->iflags = 0; /* clear interrupt condition */ - card->wandev.critical = 0; - restore_flags(host_cpu_flags); - - if(card->buff_int_mode_unbusy) - { - x25_channel_t *chan; - - dev = card->wandev.dev; - while (dev) { - chan = dev->priv; - if(chan->devtint) { - mark_bh(NET_BH); - return; - } - - dev = chan->slave; - } - } } -/*============================================================================ - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * coming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. +/* + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * coming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. */ static void rx_intr (sdla_t* card) { TX25Mbox* rxmb = card->rxmb; - unsigned lcn = rxmb->cmd.lcn; /* logical channel number */ - unsigned len = rxmb->cmd.length; /* packet length */ - unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ - wan_device_t* wandev = &card->wandev; - struct net_device* dev = get_dev_by_lcn(wandev, lcn); + unsigned lcn = rxmb->cmd.lcn; + netdevice_t* dev = find_channel(card,lcn); x25_channel_t* chan; - struct sk_buff* skb; - void* bufptr; + struct sk_buff* skb=NULL; - if (dev == NULL) - { + if (dev == NULL){ /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", card->devname, lcn); @@ -957,279 +1760,741 @@ chan = dev->priv; chan->i_timeout_sofar = jiffies; - if (chan->drop_sequence) - { - if (!(qdm & 0x01)) chan->drop_sequence = 0; + + + /* Copy the data from the board, into an + * skb buffer + */ + if (wanpipe_pull_data_in_skb(card,dev,&skb)){ + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_no_socket; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; return; } - skb = chan->rx_skb; - if (skb == NULL) - { - /* Allocate new socket buffer */ - int bufsize = (qdm & 0x01) ? dev->mtu : len; + dev->last_rx = jiffies; /* timestamp */ - skb = dev_alloc_skb(bufsize + dev->hard_header_len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; /* set flag */ + + /* ------------ API ----------------*/ + + if (chan->common.usedby == API){ + + if (bh_enqueue(dev, skb)){ ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + wan_dev_kfree_skb(skb, FREE_READ); return; - } - skb->dev = dev; - skb->protocol = htons(chan->protocol); - chan->rx_skb = skb; - } + } - if (skb_tailroom(skb) < len) - { - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb); - chan->rx_skb = NULL; - if (qdm & 0x01) chan->drop_sequence = 1; + ++chan->ifstats.rx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.rx_bytes += skb->len; + #endif + - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; + chan->rx_skb = NULL; + if (!test_and_set_bit(0, &chan->tq_working)){ + wanpipe_queue_tq(&chan->common.wanpipe_task); + wanpipe_mark_bh(); + } return; } - /* Append packet to the socket buffer */ - bufptr = skb_put(skb, len); - memcpy(bufptr, rxmb->data, len); - - if (qdm & 0x01) - return; /* more data is coming */ - - dev->last_rx = jiffies; /* timestamp */ - chan->rx_skb = NULL; /* dequeue packet */ + /* ------------- WANPIPE -------------------*/ + + /* set rx_skb to NULL so we won't access it later when kernel already owns it */ + chan->rx_skb=NULL; + /* Decapsulate packet, if necessary */ - if (!skb->protocol && !wanrouter_type_trans(skb, dev)) - { + if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ /* can't decapsulate packet */ - dev_kfree_skb(skb); + wan_dev_kfree_skb(skb, FREE_READ); ++chan->ifstats.rx_errors; - } - else - { - if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) - { - if( card->wandev.enable_IPX ) - { - if(chan_send(dev, skb)) - { + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + + }else{ + if( handle_IPXWAN(skb->data, chan->name, + chan->enable_IPX, chan->network_number, + skb->protocol)){ + + if( chan->enable_IPX ){ + if(chan_send(dev, skb->data, skb->len,0)){ chan->tx_skb = skb; + }else{ + wan_dev_kfree_skb(skb, FREE_WRITE); + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; } - else - { - dev_kfree_skb(skb); - } - } - else - { - /* FIXME: increment IPX packet dropped statistic */ + }else{ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; } - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; + }else{ + skb->mac.raw = skb->data; + #if defined(LINUX_2_1) || defined(LINUX_2_4) chan->ifstats.rx_bytes += skb->len; + #endif + ++chan->ifstats.rx_packets; + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + netif_rx(skb); } } + + return; } -/*============================================================================ - * Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag - */ -static void tx_intr (sdla_t* card) +static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb) { - struct net_device *dev; - x25_channel_t *chan; + void *bufptr; + TX25Mbox* rxmb = card->rxmb; + unsigned len = rxmb->cmd.length; /* packet length */ + unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ + x25_channel_t *chan = dev->priv; + struct sk_buff *new_skb = *skb; + + if (chan->common.usedby == WANPIPE){ + if (chan->drop_sequence){ + if (!(qdm & 0x01)){ + chan->drop_sequence = 0; + } + return 1; + } + new_skb = chan->rx_skb; + }else{ + /* Add on the API header to the received + * data + */ + len += sizeof(x25api_hdr_t); + } + + if (new_skb == NULL){ + int bufsize; - /* unbusy all devices and then dev_tint(); */ - dev = card->wandev.dev; - while (dev) { - chan->devtint = dev->tbusy; - dev->tbusy = 0; + if (chan->common.usedby == WANPIPE){ + bufsize = (qdm & 0x01) ? dev->mtu : len; + }else{ + bufsize = len; + } - dev = chan->slave; + /* Allocate new socket buffer */ + new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + chan->drop_sequence = 1; /* set flag */ + ++chan->ifstats.rx_dropped; + return 1; + } } -} + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_dev_kfree_skb(new_skb, FREE_READ); + if (chan->common.usedby == WANPIPE){ + chan->rx_skb = NULL; + if (qdm & 0x01){ + chan->drop_sequence = 1; + } + } -/*============================================================================ - * Modem status interrupt handler. - */ -static void status_intr (sdla_t* card) -{ -} + printk(KERN_INFO "%s: unexpectedly long packet sequence " + "on interface %s!\n", card->devname, dev->name); + ++chan->ifstats.rx_length_errors; + return 1; + } -/*============================================================================ - * Network event interrupt handler. - */ -static void event_intr (sdla_t* card) -{ -} + bufptr = skb_put(new_skb,len); -/*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ -static void spur_intr (sdla_t* card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} -/****** Background Polling Routines ****************************************/ + if (chan->common.usedby == API){ + /* Fill in the x25api header + */ + x25api_t * api_data = (x25api_t*)bufptr; + api_data->hdr.qdm = rxmb->cmd.qdm; + api_data->hdr.cause = rxmb->cmd.cause; + api_data->hdr.diagn = rxmb->cmd.diagn; + api_data->hdr.length = rxmb->cmd.length; + memcpy(api_data->data, rxmb->data, rxmb->cmd.length); + }else{ + memcpy(bufptr, rxmb->data, len); + } + + new_skb->dev = dev; + + if (chan->common.usedby == API){ + new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(X25_PROT); + new_skb->pkt_type = WAN_PACKET_DATA; + }else{ + new_skb->protocol = chan->protocol; + chan->rx_skb = new_skb; + } + + /* If qdm bit is set, more data is coming + * thus, exit and wait for more data before + * sending the packet up. (Used by router only) + */ + if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) + return 1; + + *skb = new_skb; -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. + return 0; +} + +/*=============================================================== + * tx_intr + * + * Transmit interrupt handler. + * For each dev, check that there is something to send. + * If data available, transmit. * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ + *===============================================================*/ -static void wpx_poll (sdla_t* card) +static void tx_intr (sdla_t* card) { - unsigned long host_cpu_flags; - - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; + netdevice_t *dev; + TX25Status* status = card->flags; + unsigned char more_to_tx=0; + x25_channel_t *chan=NULL; + int i=0; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "%s: critical in polling!\n",card->devname); - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; + if (card->u.x.tx_dev == NULL){ + card->u.x.tx_dev = card->wandev.dev; } - switch(card->wandev.state) - { - case WAN_CONNECTED: - poll_active(card); - break; + dev = card->u.x.tx_dev; - case WAN_CONNECTING: - poll_connecting(card); - break; + for (;;){ - case WAN_DISCONNECTED: - poll_disconnected(card); + chan = dev->priv; + if (chan->transmit_length){ + /* Device was set to transmit, check if the TX + * buffers are available + */ + if (chan->common.state != WAN_CONNECTED){ + chan->transmit_length = 0; + atomic_set(&chan->common.driver_busy,0); + chan->tx_offset=0; + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + dev = move_dev_to_next(card,dev); + break; + } + + if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && + (*card->u.x.hdlc_buf_status & 0x40) ){ + /* Tx buffer available, we can send */ + + if (tx_intr_send(card, dev)){ + more_to_tx=1; + } + + /* If more than one interface present, move the + * device pointer to the next interface, so on the + * next TX interrupt we will try sending from it. + */ + dev = move_dev_to_next(card,dev); + break; + }else{ + /* Tx buffers not available, but device set + * the TX interrupt. Set more_to_tx and try + * to transmit for other devices. + */ + more_to_tx=1; + dev = move_dev_to_next(card,dev); + } + + }else{ + /* This device was not set to transmit, + * go to next + */ + dev = move_dev_to_next(card,dev); + } + + if (++i == card->u.x.no_dev){ + if (!more_to_tx){ + DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", + card->devname); + } + break; + } + + } //End of FOR + + card->u.x.tx_dev = dev; + + if (!more_to_tx){ + /* if any other interfaces have transmit interrupts pending, */ + /* do not disable the global transmit interrupt */ + if (!(--card->u.x.tx_interrupts_pending)){ + status->imask &= ~INTR_ON_TX_FRAME; + } } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + return; } -/*============================================================================ - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. - */ -static void poll_connecting (sdla_t* card) +/*=============================================================== + * move_dev_to_next + * + * + *===============================================================*/ + + +netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + if (card->u.x.no_dev != 1){ + if (*((netdevice_t**)dev->priv) == NULL){ + return card->wandev.dev; + }else{ + return *((netdevice_t**)dev->priv); + } + } + return dev; +} + +/*=============================================================== + * tx_intr_send + * + * + *===============================================================*/ + +static int tx_intr_send(sdla_t *card, netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + + if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ + + /* Packet was split up due to its size, do not disable + * tx_intr + */ + return 1; + } + + chan->transmit_length=0; + atomic_set(&chan->common.driver_busy,0); + chan->tx_offset=0; + + /* If we are in API mode, wakeup the + * sock BH handler, not the NET_BH */ + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + return 0; +} + + +/*=============================================================== + * timer_intr + * + * Timer interrupt handler. + * Check who called the timer interrupt and perform + * action accordingly. + * + *===============================================================*/ + +static void timer_intr (sdla_t *card) { TX25Status* status = card->flags; - if (status->gflags & X25_HDLC_ABM) - { + if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ + + if (timer_intr_cmd_exec(card) == 0){ + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_CMD_EXEC; + } + + }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { + + if ((*card->u.x.hdlc_buf_status & 0x40) && + card->u.x.udp_type == UDP_XPIPE_TYPE){ + + if(process_udp_mgmt_pkt(card)) { + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_UDP_PKT; + } + } + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { + + netdevice_t *dev = card->u.x.poll_device; + x25_channel_t *chan = NULL; + + if (!dev){ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + return; + } + chan = dev->priv; + + printk(KERN_INFO + "%s: Closing down Idle link %s on LCN %d\n", + card->devname,chan->name,chan->common.lcn); + chan->i_timeout_sofar = jiffies; + chan_disc(dev); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + card->u.x.poll_device=NULL; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { + wanpipe_set_state(card, WAN_CONNECTED); - x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ - status->imask &= ~0x2; /* mask Tx interrupts */ + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev = card->wandev.dev; + set_chan_state(dev,WAN_CONNECTED); + send_delayed_cmd_result(card,dev,card->mbox); + } + + /* 0x8F enable all interrupts */ + x25_set_intr_mode(card, INTR_ON_RX_FRAME| + INTR_ON_TX_FRAME| + INTR_ON_MODEM_STATUS_CHANGE| + //INTR_ON_COMMAND_COMPLETE| + X25_ASY_TRANS_INTR_PENDING | + INTR_ON_TIMER | + DIRECT_RX_INTR_USAGE + ); + + status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { + + //printk(KERN_INFO "Poll connect, Turning OFF\n"); + disconnect(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { + + //printk(KERN_INFO "POll disconnect, trying to connect\n"); + connect(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + + if (*card->u.x.hdlc_buf_status & 0x40){ + x25_get_err_stats(card); + x25_get_stats(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + } + } + + if(!card->u.x.timer_int_enabled){ + //printk(KERN_INFO "Turning Timer Off \n"); + status->imask &= ~INTR_ON_TIMER; } - else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) - disconnect(card); } -/*============================================================================ - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, connect - * link. +/*==================================================================== + * Modem status interrupt handler. + *===================================================================*/ +static void status_intr (sdla_t* card) +{ + + /* Added to avoid Modem status message flooding */ + static TX25ModemStatus last_stat; + + TX25Mbox* mbox = card->mbox; + TX25ModemStatus *modem_status; + netdevice_t *dev; + x25_channel_t *chan; + int err; + + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_READ_MODEM_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err){ + x25_error(card, err, X25_READ_MODEM_STATUS, 0); + }else{ + + modem_status = (TX25ModemStatus*)mbox->data; + + /* Check if the last status was the same + * if it was, do NOT print message again */ + + if (last_stat.status != modem_status->status){ + + printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", + card->devname,DCD(modem_status->status),CTS(modem_status->status)); + + last_stat.status = modem_status->status; + + if (card->u.x.oob_on_modem){ + + mbox->cmd.pktType = mbox->cmd.command; + mbox->cmd.result = 0x08; + + /* Send a OOB to all connected sockets */ + for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){ + chan=dev->priv; + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mbox); + } + } + + /* The modem OOB message will probably kill the + * the link. If we don't clear the flag here, + * a deadlock could occur */ + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + } + } + } + + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_LINK_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err){ + x25_error(card, err, X25_HDLC_LINK_STATUS, 0); + } + +} + +/*==================================================================== + * Network event interrupt handler. + *===================================================================*/ +static void event_intr (sdla_t* card) +{ + x25_fetch_events(card); +} + +/*==================================================================== + * Spurious interrupt handler. + * o print a warning + * o + *====================================================================*/ + +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + + +/* + * Background Polling Routines */ + +/*==================================================================== + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + *====================================================================*/ + +static void wpx_poll (sdla_t *card) +{ + if (!card->wandev.dev){ + goto wpx_poll_exit; + } + + if (card->open_cnt != card->u.x.num_of_ch){ + goto wpx_poll_exit; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + switch(card->wandev.state){ + case WAN_CONNECTED: + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + } + +wpx_poll_exit: + clear_bit(POLL_CRIT,&card->wandev.critical); + return; +} + +static void trigger_x25_poll(sdla_t *card) +{ + #ifdef LINUX_2_4 + schedule_task(&card->u.x.x25_poll_task); + #else + queue_task(&card->u.x.x25_poll_task, &tq_scheduler); + #endif +} + +/*==================================================================== + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. + *===================================================================*/ + +static void poll_connecting (sdla_t* card) +{ + volatile TX25Status* status = card->flags; + + if (status->gflags & X25_HDLC_ABM){ + + timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); + + }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ + + timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); + + } +} + +/*==================================================================== + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, + * connect link. + *===================================================================*/ + static void poll_disconnected (sdla_t* card) { - if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) - connect(card); + netdevice_t *dev; + x25_channel_t *chan; + TX25Status* status = card->flags; + + if (!card->u.x.LAPB_hdlc && card->open_cnt && + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ + timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + } + + + if ((dev=card->wandev.dev) == NULL) + return; + + if ((chan=dev->priv) == NULL) + return; + + if (chan->common.usedby == API && + atomic_read(&chan->common.command) && + card->u.x.LAPB_hdlc){ + + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; + + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; + } + } -/*============================================================================ - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. - */ +/*==================================================================== + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. + *===================================================================*/ + static void poll_active (sdla_t* card) { - struct net_device* dev; - - /* Fetch X.25 asynchronous events */ - x25_fetch_events(card); + netdevice_t* dev; + TX25Status* status = card->flags; - dev = card->wandev.dev; - while (dev) { + for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){ x25_channel_t* chan = dev->priv; - struct sk_buff* skb = chan->tx_skb; - - /* If there is a packet queued for transmission then kick - * the channel's send routine. When transmission is complete - * or if error has occurred, release socket buffer and reset - * 'tbusy' flag. - */ - if (skb && (chan_send(dev, skb) == 0)) - { - chan->tx_skb = NULL; - dev->tbusy = 0; - dev_kfree_skb(skb); - } /* If SVC has been idle long enough, close virtual circuit */ - - if(( chan->svc )&&( chan->state == WAN_CONNECTED )) - { - if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ) - { + if ( chan->common.svc && + chan->common.state == WAN_CONNECTED && + chan->common.usedby == WANPIPE ){ + + if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ /* Close svc */ - printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn); - chan->i_timeout_sofar = jiffies; - chan_disc(dev); + card->u.x.poll_device=dev; + timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); } } - dev = chan->slave; +#ifdef PRINT_DEBUG + chan->ifstats.tx_compressed = atomic_read(&chan->common.command); + chan->ifstats.tx_errors = chan->common.state; + chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); + ++chan->ifstats.tx_bytes; + + chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); + chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); + chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; +#endif + + if (chan->common.usedby == API && + atomic_read(&chan->common.command) && + !card->u.x.LAPB_hdlc){ + + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; + + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; + } + + if ((chan->common.usedby == API) && + atomic_read(&chan->common.disconnect)){ + + if (chan->common.state == WAN_DISCONNECTED){ + atomic_set(&chan->common.disconnect,0); + return; + } + + atomic_set(&chan->common.command,X25_CLEAR_CALL); + if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; + + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; + } } } -/****** SDLA Firmware-Specific Functions ************************************* - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be dealt with - * immediately. To tackle with this problem we execute each interface command - * in a loop until good return code is received or maximum number of retries - * is reached. Each interface command returns non-zero return code, an - * asynchronous event/error handler x25_error() is called. - */ +static void timer_intr_exec(sdla_t *card, unsigned char TYPE) +{ + TX25Status* status = card->flags; + card->u.x.timer_int_enabled |= TYPE; + if (!(status->imask & INTR_ON_TIMER)) + status->imask |= INTR_ON_TIMER; +} + + +/*==================================================================== + * SDLA Firmware-Specific Functions + * + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface + * command in a loop until good return code is received or maximum number + * of retries is reached. Each interface command returns non-zero return + * code, an asynchronous event/error handler x25_error() is called. + *====================================================================*/ + +/*==================================================================== + * Read X.25 firmware version. + * Put code version as ASCII string in str. + *===================================================================*/ -/*============================================================================ - * Read X.25 firmware version. - * Put code version as ASCII string in str. - */ static int x25_get_version (sdla_t* card, char* str) { TX25Mbox* mbox = card->mbox; @@ -1247,15 +2512,16 @@ if (!err && str) { int len = mbox->cmd.length; + memcpy(str, mbox->data, len); str[len] = '\0'; } return err; } -/*============================================================================ - * Configure adapter. - */ +/*==================================================================== + * Configure adapter. + *===================================================================*/ static int x25_configure (sdla_t* card, TX25Config* conf) { @@ -1263,8 +2529,7 @@ int retry = MAX_CMD_RETRY; int err; - do - { + do{ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); mbox->cmd.length = sizeof(TX25Config); @@ -1274,9 +2539,51 @@ return err; } -/*============================================================================ +/*==================================================================== + * Configure adapter for HDLC only. + *===================================================================*/ + +static int hdlc_configure (sdla_t* card, TX25Config* conf) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); + mbox->cmd.length = sizeof(TX25Config); + mbox->cmd.command = X25_HDLC_SET_CONFIG; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); + + return err; +} + +static int set_hdlc_level (sdla_t* card) +{ + + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = SET_PROTOCOL_LEVEL; + mbox->cmd.length = 1; + mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); + + return err; +} + + + +/*==================================================================== * Get communications error statistics. - */ + *====================================================================*/ + static int x25_get_err_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1289,7 +2596,7 @@ mbox->cmd.command = X25_HDLC_READ_COMM_ERR; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - + if (!err) { THdlcCommErr* stats = (void*)mbox->data; @@ -1302,9 +2609,10 @@ return err; } -/*============================================================================ - * Get protocol statistics. - */ +/*==================================================================== + * Get protocol statistics. + *===================================================================*/ + static int x25_get_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1316,21 +2624,22 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); + } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; if (!err) { TX25Stats* stats = (void*)mbox->data; card->wandev.stats.rx_packets = stats->rxData; - card->wandev.stats.tx_packets = stats->rxData; + card->wandev.stats.tx_packets = stats->txData; } return err; } -/*============================================================================ - * Close HDLC link. - */ +/*==================================================================== + * Close HDLC link. + *===================================================================*/ + static int x25_close_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1343,13 +2652,15 @@ mbox->cmd.command = X25_HDLC_LINK_CLOSE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - + return err; } -/*============================================================================ - * Open HDLC link. - */ + +/*==================================================================== + * Open HDLC link. + *===================================================================*/ + static int x25_open_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1362,13 +2673,13 @@ mbox->cmd.command = X25_HDLC_LINK_OPEN; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - + return err; } -/*============================================================================ +/*===================================================================== * Setup HDLC link. - */ + *====================================================================*/ static int x25_setup_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1385,9 +2696,10 @@ return err; } -/*============================================================================ +/*==================================================================== * Set (raise/drop) DTR. - */ + *===================================================================*/ + static int x25_set_dtr (sdla_t* card, int dtr) { TX25Mbox* mbox = card->mbox; @@ -1404,13 +2716,14 @@ mbox->cmd.command = X25_SET_GLOBAL_VARS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - + return err; } -/*============================================================================ - * Set interrupt mode. - */ +/*==================================================================== + * Set interrupt mode. + *===================================================================*/ + static int x25_set_intr_mode (sdla_t* card, int mode) { TX25Mbox* mbox = card->mbox; @@ -1421,30 +2734,32 @@ { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->data[0] = mode; - if (card->hw.fwid == SFID_X25_508) - { + if (card->hw.fwid == SFID_X25_508){ mbox->data[1] = card->hw.irq; - mbox->cmd.length = 2; + mbox->data[2] = 2; + mbox->cmd.length = 3; + }else { + mbox->cmd.length = 1; } - else mbox->cmd.length = 1; mbox->cmd.command = X25_SET_INTERRUPT_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; + } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); + return err; } -/*============================================================================ - * Read X.25 channel configuration. - */ +/*==================================================================== + * Read X.25 channel configuration. + *===================================================================*/ + static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) { TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; - int lcn = chan->lcn; + int lcn = chan->common.lcn; int err; - do - { + do{ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.lcn = lcn; mbox->cmd.command = X25_READ_CHANNEL_CONFIG; @@ -1456,19 +2771,25 @@ TX25Status* status = card->flags; /* calculate an offset into the array of status bytes */ - if (card->u.x.hi_svc <= 255) + if (card->u.x.hi_svc <= X25_MAX_CHAN){ + chan->ch_idx = lcn - 1; - else - { + + }else{ int offset; - switch (mbox->data[0] && 0x1F) + /* FIX: Apr 14 2000 : Nenad Corbic + * The data field was being compared to 0x1F using + * '&&' instead of '&'. + * This caused X25API to fail for LCNs greater than 255. + */ + switch (mbox->data[0] & 0x1F) { - case 0x01: + case 0x01: offset = status->pvc_map; break; - case 0x03: + case 0x03: offset = status->icc_map; break; - case 0x07: + case 0x07: offset = status->twc_map; break; case 0x0B: offset = status->ogc_map; break; @@ -1481,37 +2802,38 @@ /* get actual transmit packet size on this channel */ switch(mbox->data[1] & 0x38) { - case 0x00: - chan->tx_pkt_size = 16; + case 0x00: + chan->tx_pkt_size = 16; break; - case 0x08: - chan->tx_pkt_size = 32; + case 0x08: + chan->tx_pkt_size = 32; break; - case 0x10: - chan->tx_pkt_size = 64; + case 0x10: + chan->tx_pkt_size = 64; break; - case 0x18: - chan->tx_pkt_size = 128; + case 0x18: + chan->tx_pkt_size = 128; break; - case 0x20: - chan->tx_pkt_size = 256; + case 0x20: + chan->tx_pkt_size = 256; break; - case 0x28: - chan->tx_pkt_size = 512; + case 0x28: + chan->tx_pkt_size = 512; break; - case 0x30: - chan->tx_pkt_size = 1024; + case 0x30: + chan->tx_pkt_size = 1024; break; } - printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", - card->devname, lcn, chan->tx_pkt_size); + if (card->u.x.logging) + printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", + card->devname, lcn, chan->tx_pkt_size); } return err; } -/*============================================================================ - * Place X.25 call. - */ +/*==================================================================== + * Place X.25 call. + *====================================================================*/ static int x25_place_call (sdla_t* card, x25_channel_t* chan) { @@ -1520,7 +2842,15 @@ int err; char str[64]; - sprintf(str, "-d%s -uCC", chan->addr); + + if (chan->protocol == htons(ETH_P_IP)){ + sprintf(str, "-d%s -uCC", chan->addr); + + }else if (chan->protocol == htons(ETH_P_IPX)){ + sprintf(str, "-d%s -u800000008137", chan->addr); + + } + do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); @@ -1530,17 +2860,15 @@ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); - if (!err) - { - chan->lcn = mbox->cmd.lcn; - chan->protocol = ETH_P_IP; + if (!err){ + bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); } return err; } -/*============================================================================ - * Accept X.25 call. - */ +/*==================================================================== + * Accept X.25 call. + *====================================================================*/ static int x25_accept_call (sdla_t* card, int lcn, int qdm) { @@ -1556,13 +2884,14 @@ mbox->cmd.command = X25_ACCEPT_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - + return err; } -/*============================================================================ - * Clear X.25 call. - */ +/*==================================================================== + * Clear X.25 call. + *====================================================================*/ + static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) { TX25Mbox* mbox = card->mbox; @@ -1578,35 +2907,59 @@ mbox->cmd.command = X25_CLEAR_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - + return err; } -/*============================================================================ - * Send X.25 data packet. - */ +/*==================================================================== + * Send X.25 data packet. + *====================================================================*/ + static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) { TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - + unsigned char cmd; + + if (card->u.x.LAPB_hdlc) + cmd = X25_HDLC_WRITE; + else + cmd = X25_WRITE; + do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); memcpy(mbox->data, buf, len); mbox->cmd.length = len; mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_WRITE; + + if (card->u.x.LAPB_hdlc){ + mbox->cmd.pf = qdm; + }else{ + mbox->cmd.qdm = qdm; + } + + mbox->cmd.command = cmd; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn)); + } while (err && retry-- && x25_error(card, err, cmd , lcn)); + + + /* If buffers are busy the return code for LAPB HDLC is + * 1. The above functions are looking for return code + * of X25RES_NOT_READY if busy. */ + + if (card->u.x.LAPB_hdlc && err == 1){ + err = X25RES_NOT_READY; + } + return err; } -/*============================================================================ - * Fetch X.25 asynchronous events. - */ +/*==================================================================== + * Fetch X.25 asynchronous events. + *===================================================================*/ + static int x25_fetch_events (sdla_t* card) { TX25Status* status = card->flags; @@ -1618,25 +2971,26 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_IS_DATA_AVAILABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); } return err; } -/*============================================================================ - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns non-zero - * return code to handle X.25 asynchronous events and common errors. - * Return non-zero to repeat command or zero to cancel it. - * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. - */ +/*==================================================================== + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns + * non-zero return code to handle X.25 asynchronous events and + * common errors. Return non-zero to repeat command or zero to + * cancel it. + * + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. + *====================================================================*/ + static int x25_error (sdla_t* card, int err, int cmd, int lcn) { int retry = 1; @@ -1651,138 +3005,212 @@ return 0; } memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); - switch (err) - { - case 0x40: /* X.25 asynchronous packet was received */ - mb->data[dlen] = '\0'; - switch (mb->cmd.pktType & 0x7F) - { - case 0x30: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; + switch (err){ - case 0x31: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case 0x02: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; + case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ - case 0x04: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - break; + mb->data[dlen] = '\0'; - case 0x08: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; + switch (mb->cmd.pktType & 0x7F){ - default: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } + case ASE_CALL_RQST: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); break; - case 0x41: /* X.25 protocol violation indication */ - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + case ASE_CALL_ACCEPTED: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); break; - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); + case ASE_CLEAR_RQST: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); break; - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); + case ASE_RESET_RQST: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn); + api_oob_event (card,mb); break; - case 0x08: /* modem failure */ - printk(KERN_INFO "%s: modem failure!\n", card->devname); + case ASE_RESTART_RQST: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); + case ASE_CLEAR_CONFRM: + if (clear_confirm_event (card,mb)) + break; + + /* I use the goto statement here so if + * somebody inserts code between the + * case and default, we will not have + * ghost problems */ + + goto dflt_1; + + default: +dflt_1: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.pktType, + mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); + } + break; + + case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ + + /* Bug Fix: Mar 14 2000 + * The Protocol violation error conditions were + * not handeled previously */ + + switch (mb->cmd.pktType & 0x7F){ + + case PVE_CLEAR_RQST: /* Clear request */ + retry = call_cleared(card, cmd, lcn, mb); + break; + + case PVE_RESET_RQST: /* Reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn); + api_oob_event (card,mb); break; - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); + case PVE_RESTART_RQST: /* Restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - retry = 0; /* abort command */ + default : + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, + mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + api_oob_event(card,mb); + } + break; + + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; + + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) + ; + break; + + case 0x08: /* modem failure */ + #ifndef MODEM_NOT_LOG + printk(KERN_INFO "%s: modem failure!\n", card->devname); + #endif MODEM_NOT_LOG + api_oob_event(card,mb); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname); + api_oob_event(card,mb); + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->data[0]); + api_oob_event(card,mb); + break; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd) + ; + retry = 0; /* abort command */ + break; + + case X25RES_NOT_READY: + retry = 1; + break; + + case 0x01: + if (card->u.x.LAPB_hdlc) break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - retry = 0; /* abort command */ + if (mb->cmd.command == 0x16) + break; + /* I use the goto statement here so if + * somebody inserts code between the + * case and default, we will not have + * ghost problems */ + goto dflt_2; + + default: +dflt_2: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", + card->devname, cmd, err, mb->cmd.lcn) + ; + retry = 0; /* abort command */ } kfree(mb); return retry; } -/****** X.25 Asynchronous Event Handlers ************************************* - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. - */ +/*==================================================================== + * X.25 Asynchronous Event Handlers + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. + *====================================================================*/ -/*============================================================================ - * Handle X.25 incoming call request. + + +/*==================================================================== + *Handle X.25 incoming call request. * RFC 1356 establishes the following rules: * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation. - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when - * clearing a call because protocol encapsulation is not supported. - * 4. If an incoming call is received while a call request is pending - * (i.e. call collision has occurred), the incoming call shall be - * rejected and call request shall be retried. - */ + * request packet contains NLPID identifying protocol encapsulation + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used + * when clearing a call because protocol encapsulation is not + * supported. + * 4. If an incoming call is received while a call request is + * pending (i.e. call collision has occured), the incoming call + * shall be rejected and call request shall be retried. + *====================================================================*/ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; int new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); + netdevice_t* dev = get_dev_by_lcn(wandev, new_lcn); x25_channel_t* chan = NULL; int accept = 0; /* set to '1' if o.k. to accept call */ + unsigned int user_data; x25_call_info_t* info; - + /* Make sure there is no call collision */ if (dev != NULL) { printk(KERN_INFO "%s: X.25 incoming call collision on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); return 1; } /* Make sure D bit is not set in call request */ - if (mb->cmd.qdm & 0x02) - { - printk(KERN_INFO - "%s: X.25 incoming call on LCN %d with D-bit set!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } +//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT +// if (mb->cmd.qdm & 0x02) +// { +// printk(KERN_INFO +// "%s: X.25 incoming call on LCN %d with D-bit set!\n", +// card->devname, new_lcn); +// +// x25_clear_call(card, new_lcn, 0, 0); +// return 1; +// } /* Parse call request data */ info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); @@ -1794,90 +3222,120 @@ x25_clear_call(card, new_lcn, 0, 0); return 1; } + parse_call_info(mb->data, info); - printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", - card->devname, new_lcn, mb->data); + + if (card->u.x.logging) + printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", + card->devname, new_lcn); + + /* Conver the first two ASCII characters into an + * interger. Used to check the incoming protocol + */ + user_data = hex_to_uint(info->user,2); /* Find available channel */ - dev = wandev->dev; - while (dev) { + for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){ chan = dev->priv; - if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + if (chan->common.usedby == API) continue; + + if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) + continue; + + if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ + printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", + htons(chan->protocol), info->user[0]); + continue; + } + + if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ + printk(KERN_INFO "IPX packet but configured for IP: %x\n", + htons(chan->protocol)); + continue; + } if (strcmp(info->src, chan->addr) == 0) break; + /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) break; - - dev = chan->slave; } - if (dev == NULL) - { - printk(KERN_INFO "%s: no channels available!\n", - card->devname); - x25_clear_call(card, new_lcn, 0, 0); - } + if (dev == NULL){ + + /* If the call is not for any WANPIPE interfaces + * check to see if there is an API listening queue + * waiting for data. If there is send the packet + * up the stack. + */ + if (card->sk != NULL && card->func != NULL){ + if (api_incoming_call(card,mb,new_lcn)){ + x25_clear_call(card, new_lcn, 0, 0); + } + accept = 0; + }else{ + printk(KERN_INFO "%s: no channels available!\n", + card->devname); + + x25_clear_call(card, new_lcn, 0, 0); + } + + }else if (info->nuser == 0){ - /* Check requested protocol encapsulation */ - else if (info->nuser == 0) - { printk(KERN_INFO "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn); + card->devname, new_lcn) + ; x25_clear_call(card, new_lcn, 0, 0); - } - else switch (info->user[0]) - { + + }else switch (info->user[0]){ + case 0: /* multiplexed */ - chan->protocol = 0; + chan->protocol = htons(0); accept = 1; break; case NLPID_IP: /* IP datagrams */ - chan->protocol = ETH_P_IP; accept = 1; break; case NLPID_SNAP: /* IPX datagrams */ - chan->protocol = ETH_P_IPX; accept = 1; break; + default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X in incoming call " "on LCN %d!\n", card->devname, info->user[0], new_lcn); x25_clear_call(card, new_lcn, 0, 249); } + + if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ - if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) - { - chan->lcn = new_lcn; + bind_lcn_to_dev (card, chan->dev, new_lcn); + if (x25_get_chan_conf(card, chan) == CMD_OK) set_chan_state(dev, WAN_CONNECTED); - else + else x25_clear_call(card, new_lcn, 0, 0); } kfree(info); return 1; } -/*============================================================================ - * Handle accepted call. - */ +/*==================================================================== + * Handle accepted call. + *====================================================================*/ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + netdevice_t* dev = find_channel(card, new_lcn); x25_channel_t* chan; - printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n", - card->devname, new_lcn); - if (dev == NULL) - { + if (dev == NULL){ printk(KERN_INFO "%s: clearing orphaned connection on LCN %d!\n", card->devname, new_lcn); @@ -1885,6 +3343,10 @@ return 1; } + if (card->u.x.logging) + printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", + card->devname, dev->name, new_lcn); + /* Get channel configuration and notify router */ chan = dev->priv; if (x25_get_chan_conf(card, chan) != CMD_OK) @@ -1892,178 +3354,256 @@ x25_clear_call(card, new_lcn, 0, 0); return 1; } + set_chan_state(dev, WAN_CONNECTED); + + if (chan->common.usedby == API){ + send_delayed_cmd_result(card,dev,mb); + bind_lcn_to_dev (card, dev, new_lcn); + } + return 1; } -/*============================================================================ - * Handle cleared call. - */ +/*==================================================================== + * Handle cleared call. + *====================================================================*/ static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + netdevice_t* dev = find_channel(card, new_lcn); + x25_channel_t *chan; + unsigned char old_state; - printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " + if (card->u.x.logging){ + printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " "Diagn:0x%02X\n", card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - if (dev == NULL) + } + + if (dev == NULL){ + printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", + card->devname); return 1; + } + + chan=dev->priv; + + old_state = chan->common.state; + set_chan_state(dev, WAN_DISCONNECTED); + + if (chan->common.usedby == API){ + + switch (old_state){ + + case WAN_CONNECTING: + send_delayed_cmd_result(card,dev,mb); + break; + case WAN_CONNECTED: + send_oob_msg(card,dev,mb); + break; + } + } + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; } -/*============================================================================ - * Handle X.25 restart event. - */ - +/*==================================================================== + * Handle X.25 restart event. + *====================================================================*/ + static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; - struct net_device* dev; + netdevice_t* dev; + x25_channel_t *chan; + unsigned char old_state; printk(KERN_INFO "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.cause, mb->cmd.diagn); /* down all logical channels */ - dev = wandev->dev; - while (dev) { - x25_channel_t *chan = dev->priv; + for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){ + chan=dev->priv; + old_state = chan->common.state; set_chan_state(dev, WAN_DISCONNECTED); - dev = chan->slave; - } + if (chan->common.usedby == API){ + switch (old_state){ + + case WAN_CONNECTING: + send_delayed_cmd_result(card,dev,mb); + break; + case WAN_CONNECTED: + send_oob_msg(card,dev,mb); + break; + } + } + } return (cmd == X25_WRITE) ? 0 : 1; } -/*============================================================================ +/*==================================================================== * Handle timeout event. - */ + *====================================================================*/ + static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; if (mb->cmd.pktType == 0x05) /* call request time out */ { - struct net_device* dev = get_dev_by_lcn(&card->wandev, new_lcn); + netdevice_t* dev = find_channel(card,new_lcn); printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", card->devname, new_lcn); - if (dev) + + if (dev){ + x25_channel_t *chan = dev->priv; set_chan_state(dev, WAN_DISCONNECTED); - } - else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", + + if (chan->common.usedby == API){ + send_delayed_cmd_result(card,dev,card->mbox); + } + } + }else{ + printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", card->devname, mb->cmd.pktType, new_lcn); + } return 1; } -/******* Miscellaneous ******************************************************/ +/* + * Miscellaneous + */ -/*============================================================================ - * Establish physical connection. - * o open HDLC and raise DTR +/*==================================================================== + * Establish physical connection. + * o open HDLC and raise DTR * - * Return: 0 connection established - * 1 connection is in progress - * <0 error - */ + * Return: 0 connection established + * 1 connection is in progress + * <0 error + *===================================================================*/ + static int connect (sdla_t* card) { + TX25Status* status = card->flags; + if (x25_open_hdlc(card) || x25_setup_hdlc(card)) return -EIO; + wanpipe_set_state(card, WAN_CONNECTING); + + x25_set_intr_mode(card, INTR_ON_TIMER); + status->imask &= ~INTR_ON_TIMER; + return 1; } -/*============================================================================ - * Tear down physical connection. - * o close HDLC link - * o drop DTR +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR * - * Return: 0 - * <0 error + * Return: 0 + * <0 error */ + static int disconnect (sdla_t* card) { wanpipe_set_state(card, WAN_DISCONNECTED); - x25_set_intr_mode(card, 0); /* disable interrupt generation */ - x25_close_hdlc(card); /* close HDLC link */ - x25_set_dtr(card, 0); /* drop DTR */ + x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ + x25_close_hdlc(card); /* close HDLC link */ + x25_set_dtr(card, 0); /* drop DTR */ return 0; } -/*============================================================================ +/* * Find network device by its channel number. */ -static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) + +static netdevice_t* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) { - struct net_device* dev; - x25_channel_t *chan; + netdevice_t* dev; - dev = wandev->dev; - while (dev) { - if (chan->lcn == lcn) + for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)) + if (((x25_channel_t*)dev->priv)->common.lcn == lcn) break; - dev = chan->slave; - } return dev; } -/*============================================================================ - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure +/* + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call + * + * Return: 0 connected + * >0 connection in progress + * <0 failure */ -static int chan_connect (struct net_device* dev) + +static int chan_connect (netdevice_t* dev) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (chan->svc) - { - if (!chan->addr[0]) + if (chan->common.svc && chan->common.usedby == WANPIPE){ + if (!chan->addr[0]){ + printk(KERN_INFO "%s: No Destination Address\n", + card->devname); return -EINVAL; /* no destination address */ + } printk(KERN_INFO "%s: placing X.25 call to %s ...\n", card->devname, chan->addr); + if (x25_place_call(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTING); return 1; - } - else - { + }else{ if (x25_get_chan_conf(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTED); } return 0; } -/*============================================================================ - * Disconnect logical channel. - * o if SVC then clear X.25 call +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call */ -static int chan_disc (struct net_device* dev) + +static int chan_disc (netdevice_t* dev) { x25_channel_t* chan = dev->priv; - if (chan->svc) - x25_clear_call(chan->card, chan->lcn, 0, 0); + if (chan->common.svc){ + x25_clear_call(chan->card, chan->common.lcn, 0, 0); + + /* For API we disconnect on clear + * confirmation. + */ + if (chan->common.usedby == API) + return 0; + } + set_chan_state(dev, WAN_DISCONNECTED); + return 0; } -/*============================================================================ - * Set logical channel state. +/* + * Set logical channel state. */ -static void set_chan_state (struct net_device* dev, int state) + +static void set_chan_state (netdevice_t* dev, int state) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -2071,99 +3611,257 @@ save_flags(flags); cli(); - if (chan->state != state) + if (chan->common.state != state) { switch (state) { case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); - *(unsigned short*)dev->dev_addr = htons(chan->lcn); + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connected, lcn %i !\n", + card->devname, dev->name,chan->common.lcn); + } + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); chan->i_timeout_sofar = jiffies; + + /* LAPB is PVC Based */ + if (card->u.x.LAPB_hdlc) + chan->common.svc=0; break; case WAN_CONNECTING: - printk (KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connecting, lcn %i ...\n", + card->devname, dev->name, chan->common.lcn); + } break; case WAN_DISCONNECTED: - printk (KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - if (chan->svc) - { + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s disconnected, lcn %i !\n", + card->devname, dev->name,chan->common.lcn); + } + atomic_set(&chan->common.disconnect,0); + + if (chan->common.svc) { *(unsigned short*)dev->dev_addr = 0; - chan->lcn = 0; + card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; + chan->common.lcn = 0; + } + + if (chan->transmit_length){ + chan->transmit_length=0; + atomic_set(&chan->common.driver_busy,0); + chan->tx_offset=0; + if (is_queue_stopped(dev)){ + wake_net_dev(dev); + } + } + atomic_set(&chan->common.command,0); + break; + + case WAN_DISCONNECTING: + if (card->u.x.logging){ + printk (KERN_INFO + "\n%s: interface %s disconnecting, lcn %i ...\n", + card->devname, dev->name,chan->common.lcn); } + atomic_set(&chan->common.disconnect,0); break; } - chan->state = state; + chan->common.state = state; } chan->state_tick = jiffies; restore_flags(flags); } -/*============================================================================ - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data space - * points to the transmit socket buffer. When transmission is complete, - * release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. +/* + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data + * space points to the transmit socket buffer. When transmission + * is complete, release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. */ -static int chan_send (struct net_device* dev, struct sk_buff* skb) + +static int chan_send (netdevice_t* dev, void* buff, unsigned data_len, unsigned char tx_intr) { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; TX25Status* status = card->flags; - unsigned len, qdm; + unsigned len=0, qdm=0, res=0, orig_len = 0; + void *data; /* Check to see if channel is ready */ - if (!(status->cflags[chan->ch_idx] & 0x40)) - return 1; - - if (skb->len > chan->tx_pkt_size) - { - len = chan->tx_pkt_size; - qdm = 0x01; /* set M-bit (more data) */ + if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || + !(*card->u.x.hdlc_buf_status & 0x40)){ + + if (!tx_intr){ + setup_for_delayed_transmit (dev, buff, data_len); + return 0; + }else{ + /* By returning 0 to tx_intr the packet will be dropped */ + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", + card->devname,dev->name); + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + return 0; + } } - else /* final packet */ - { - len = skb->len; - qdm = 0; + + if (chan->common.usedby == API){ + /* Remove the API Header */ + x25api_hdr_t *api_data = (x25api_hdr_t *)buff; + + /* Set the qdm bits from the packet header + * User has the option to set the qdm bits + */ + qdm = api_data->qdm; + + orig_len = len = data_len - sizeof(x25api_hdr_t); + data = (unsigned char*)buff + sizeof(x25api_hdr_t); + }else{ + data = buff; + orig_len = len = data_len; + } + + if (tx_intr){ + /* We are in tx_intr, minus the tx_offset from + * the total length. The tx_offset part of the + * data has already been sent. Also, move the + * data pointer to proper offset location. + */ + len -= chan->tx_offset; + data = (unsigned char*)data + chan->tx_offset; } - switch(x25_send(card, chan->lcn, qdm, len, skb->data)) - { + + /* Check if the packet length is greater than MTU + * If YES: Cut the len to MTU and set the M bit + */ + if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ + len = chan->tx_pkt_size; + qdm |= M_BIT; + } + + + /* Pass only first three bits of the qdm byte to the send + * routine. In case user sets any other bit which might + * cause errors. + */ + + switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ case 0x00: /* success */ chan->i_timeout_sofar = jiffies; - if (qdm) - { - skb_pull(skb, len); - return 1; + + #ifdef LINUX_2_4 + dev->trans_start=jiffies; + #endif + + if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ + if (!tx_intr){ + /* The M bit was set, which means that part of the + * packet has been sent. Copy the packet into a buffer + * and set the offset to len, so on next tx_inter + * the packet will be sent using the below offset. + */ + chan->tx_offset += len; + + ++chan->ifstats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += len; + #endif + + if (chan->tx_offset < orig_len){ + setup_for_delayed_transmit (dev, buff, data_len); + } + res=0; + }else{ + /* We are already in tx_inter, thus data is already + * in the buffer. Update the offset and wait for + * next tx_intr. We add on to the offset, since data can + * be X number of times larger than max data size. + */ + ++chan->ifstats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += len; + #endif + + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + chan->tx_offset += len; + + /* The user can set the qdm bit as well. + * If the entire packet was sent and qdm is still + * set, than it's the user who has set the M bit. In that, + * case indicate that the packet was send by returning + * 0 and wait for a new packet. Otherwise, wait for next + * tx interrupt to send the rest of the packet */ + + if (chan->tx_offset < orig_len){ + res=1; + }else{ + res=0; + } + } + }else{ + ++chan->ifstats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + chan->ifstats.tx_bytes += len; + #endif + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + res=0; } - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += skb->len; break; case 0x33: /* Tx busy */ - return 1; + if (tx_intr){ + printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", + card->devname,dev->name); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + res=0; + }else{ + DBG_PRINTK(KERN_INFO + "%s: Send: Big Error should have tx: storring %s\n", + card->devname,dev->name); + setup_for_delayed_transmit (dev, buff, data_len); + res=1; + } + break; default: /* failure */ ++chan->ifstats.tx_errors; -/* return 1; */ + if (tx_intr){ + printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", + card->devname,dev->name); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + res=0; + }else{ + DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", + card->devname,dev->name); + setup_for_delayed_transmit (dev, buff, data_len); + res=1; + } + break; } - return 0; + return res; } -/*============================================================================ - * Parse X.25 call request data and fill x25_call_info_t structure. + +/* + * Parse X.25 call request data and fill x25_call_info_t structure. */ static void parse_call_info (unsigned char* str, x25_call_info_t* info) @@ -2172,54 +3870,45 @@ for (; *str; ++str) { int i; - unsigned ch; + unsigned char ch; + + if (*str == '-') switch (str[1]) { + + /* Take minus 2 off the maximum size so that + * last byte is 0. This way we can use string + * manipulaton functions on call information. + */ - if (*str == '-') switch (str[1]) - { case 'd': /* destination address */ - for (i = 0; i < 16; ++i) - { + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ ch = str[2+i]; - if (!is_digit(ch)) - break; + if (isspace(ch)) break; info->dest[i] = ch; } break; - + case 's': /* source address */ - for (i = 0; i < 16; ++i) - { + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ ch = str[2+i]; - if (!is_digit(ch)) - break; + if (isspace(ch)) break; info->src[i] = ch; } break; case 'u': /* user data */ - for (i = 0; i < 127; ++i) - { - ch = str[2+2*i]; - if (!is_hex_digit(ch)) - break; - info->user[i] = hex_to_uint(&str[2+2*i], 2); + for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->user[i] = ch; } info->nuser = i; break; case 'f': /* facilities */ - for (i = 0; i < 64; ++i) - { - ch = str[2+4*i]; - if (!is_hex_digit(ch)) - break; - info->facil[i].code = - hex_to_uint(&str[2+4*i], 2); - ch = str[4+4*i]; - if (!is_hex_digit(ch)) - break; - info->facil[i].parm = - hex_to_uint(&str[4+4*i], 2); + for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->facil[i] = ch; } info->nfacil = i; break; @@ -2227,14 +3916,15 @@ } } -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. +/* + * Convert line speed in bps to a number used by S502 code. */ + static unsigned char bps_to_speed_code (unsigned long bps) { unsigned char number; - if (bps <= 1200) number = 0x01 ; + if (bps <= 1200) number = 0x01; else if (bps <= 2400) number = 0x02; else if (bps <= 4800) number = 0x03; else if (bps <= 9600) number = 0x04; @@ -2251,29 +3941,36 @@ return number; } -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. +/* + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. */ + static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); + return val; } -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. +/* + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. */ + static unsigned int hex_to_uint (unsigned char* str, int len) { unsigned val, ch; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len; ++str, --len) { ch = *str; @@ -2281,8 +3978,7 @@ val = (val << 4) + (ch - (unsigned)'0'); else if (is_hex_digit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else - break; + else break; } return val; } @@ -2292,21 +3988,21 @@ { int i; - if( proto == htons(ETH_P_IPX) ) { + if( proto == ETH_P_IPX) { /* It's an IPX packet */ if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ return 1; } } else { - /* It's not IPX so pass it up the stack. */ + /* It's not IPX so pass it up the stack.*/ return 0; } if( sendpacket[16] == 0x90 && sendpacket[17] == 0x04) { - /* It's IPXWAN */ + /* It's IPXWAN */ if( sendpacket[2] == 0x02 && sendpacket[34] == 0x00) @@ -2315,19 +4011,24 @@ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP */ + * option except Unnumbered RIP/SAP + */ for(i = 41; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; + } } /* Skip over the extended Node ID option */ if( sendpacket[i] == 0x04 ) + { i += 8; + } - /* We also want to turn off all header compression opt. */ + /* We also want to turn off all header compression opt. */ for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; @@ -2364,7 +4065,9 @@ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; + } printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } @@ -2382,18 +4085,18 @@ return 1; } else { - /* If we get here its an IPX-data packet, so it'll get passed up the stack. - switch the network numbers */ + /*If we get here its an IPX-data packet, so it'll get passed up the stack. + */ + /* switch the network numbers */ switch_net_numbers(sendpacket, network_number, 1); return 0; } } /* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { @@ -2402,21 +4105,17 @@ pnetwork_number = (unsigned long)((sendpacket[6] << 24) + (sendpacket[7] << 16) + (sendpacket[8] << 8) + sendpacket[9]); + - if (!incoming) - { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if (!incoming) { + /*If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { sendpacket[6] = sendpacket[7] = sendpacket[8] = sendpacket[9] = 0x00; } - } - else - { + } else { /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) - { + if( pnetwork_number == 0) { sendpacket[6] = (unsigned char)(network_number >> 24); sendpacket[7] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2431,21 +4130,17 @@ pnetwork_number = (unsigned long)((sendpacket[18] << 24) + (sendpacket[19] << 16) + (sendpacket[20] << 8) + sendpacket[21]); - - if( !incoming ) - { + + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if( pnetwork_number == network_number) { sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; + sendpacket[21] = 0x00; } - } - else - { + } else { /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) - { + if( pnetwork_number == 0 ) { sendpacket[18] = (unsigned char)(network_number >> 24); sendpacket[19] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2457,5 +4152,1419 @@ } } /* switch_net_numbers */ + + + +/********************* X25API SPECIFIC FUNCTIONS ****************/ + + +/*=============================================================== + * find_channel + * + * Manages the lcn to device map. It increases performance + * because it eliminates the need to search through the link + * list for a device which is bounded to a specific lcn. + * + *===============================================================*/ + + +netdevice_t * find_channel(sdla_t *card, unsigned lcn) +{ + if (card->u.x.LAPB_hdlc){ + + return card->wandev.dev; + + }else{ + /* We don't know whether the incoming lcn + * is a PVC or an SVC channel. But we do know that + * the lcn cannot be for both the PVC and the SVC + * channel. + + * If the lcn number is greater or equal to 255, + * take the modulo 255 of that number. We only have + * 255 locations, thus higher numbers must be mapped + * to a number between 0 and 245. + + * We must separate pvc's and svc's since two don't + * have to be contiguous. Meaning pvc's can start + * from 1 to 10 and svc's can start from 256 to 266. + * But 256%255 is 1, i.e. CONFLICT. + */ + + + /* Highest LCN number must be less or equal to 4096 */ + if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ + + if (lcn < X25_MAX_CHAN){ + if (card->u.x.svc_to_dev_map[lcn]) + return card->u.x.svc_to_dev_map[lcn]; + + if (card->u.x.pvc_to_dev_map[lcn]) + return card->u.x.pvc_to_dev_map[lcn]; + + }else{ + int new_lcn = lcn%X25_MAX_CHAN; + if (card->u.x.svc_to_dev_map[new_lcn]) + return card->u.x.svc_to_dev_map[new_lcn]; + + if (card->u.x.pvc_to_dev_map[new_lcn]) + return card->u.x.pvc_to_dev_map[new_lcn]; + } + } + return NULL; + } +} + +void bind_lcn_to_dev (sdla_t *card, netdevice_t *dev,unsigned lcn) +{ + x25_channel_t *chan = dev->priv; + + /* Modulo the lcn number by X25_MAX_CHAN (255) + * because the lcn number can be greater than 255 + * + * We need to split svc and pvc since they don't have + * to be contigous. + */ + + if (chan->common.svc){ + card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; + }else{ + card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; + } + chan->common.lcn = lcn; +} + + + +/*=============================================================== + * x25api_bh + * + * + *==============================================================*/ + +static void x25api_bh (netdevice_t * dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + struct sk_buff *skb; + + if (atomic_read(&chan->bh_buff_used) == 0){ + printk(KERN_INFO "%s: BH Buffer Empty in BH\n", + card->devname); + clear_bit(0, &chan->tq_working); + return; + } + + while (atomic_read(&chan->bh_buff_used)){ + + /* If the sock is in the process of unlinking the + * driver from the socket, we must get out. + * This never happends but is a sanity check. */ + if (test_bit(0,&chan->common.common_critical)){ + clear_bit(0, &chan->tq_working); + return; + } + + /* If LAPB HDLC, do not drop packets if socket is + * not connected. Let the buffer fill up and + * turn off rx interrupt */ + if (card->u.x.LAPB_hdlc){ + if (chan->common.sk == NULL || chan->common.func == NULL){ + clear_bit(0, &chan->tq_working); + return; + } + } + + skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; + + if (skb == NULL){ + printk(KERN_INFO "%s: BH Skb empty for read %i\n", + card->devname,chan->bh_read); + }else{ + + if (chan->common.sk == NULL || chan->common.func == NULL){ + printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", + card->devname); + wan_dev_kfree_skb(skb, FREE_READ); + x25api_bh_cleanup(dev); + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + continue; + } + + + if (chan->common.func(skb,dev,chan->common.sk) != 0){ + /* Sock full cannot send, queue us for another + * try + */ + printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", + card->devname); + atomic_set(&chan->common.receive_block,1); + return; + }else{ + x25api_bh_cleanup(dev); + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + } + } + } + clear_bit(0, &chan->tq_working); + + return; +} + +/*=============================================================== + * x25api_bh_cleanup + * + * + *==============================================================*/ + +static int x25api_bh_cleanup (netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + TX25Status* status = card->flags; + + + ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; + + if (chan->bh_read == MAX_BH_BUFF){ + chan->bh_read=0; + }else{ + ++chan->bh_read; + } + + /* If the Receive interrupt was off, it means + * that we filled up our circular buffer. Check + * that we have space in the buffer. If so + * turn the RX interrupt back on. + */ + if (!(status->imask & INTR_ON_RX_FRAME)){ + if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ + printk(KERN_INFO "%s: BH: Turning on the interrupt\n", + card->devname); + status->imask |= INTR_ON_RX_FRAME; + } + } + + atomic_dec(&chan->bh_buff_used); + return 0; +} + + +/*=============================================================== + * bh_enqueue + * + * + *==============================================================*/ + +static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + TX25Status* status = card->flags; + + if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ + printk(KERN_INFO "%s: Bottom half buffer FULL\n", + card->devname); + return 1; + } + + ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; + + if (chan->bh_write == MAX_BH_BUFF){ + chan->bh_write=0; + }else{ + ++chan->bh_write; + } + + atomic_inc(&chan->bh_buff_used); + + if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ + printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", + card->devname); + status->imask &= ~INTR_ON_RX_FRAME; + } + + return 0; +} + + +/*=============================================================== + * timer_intr_cmd_exec + * + * Called by timer interrupt to execute a command + *===============================================================*/ + +static int timer_intr_cmd_exec (sdla_t* card) +{ + netdevice_t *dev; + unsigned char more_to_exec=0; + volatile x25_channel_t *chan=NULL; + int i=0,bad_cmd=0,err=0; + + if (card->u.x.cmd_dev == NULL){ + card->u.x.cmd_dev = card->wandev.dev; + } + + dev = card->u.x.cmd_dev; + + for (;;){ + + chan = dev->priv; + + if (atomic_read(&chan->common.command)){ + + bad_cmd = check_bad_command(card,dev); + + if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && + !bad_cmd){ + + /* Socket has died or exited, We must bring the + * channel down before anybody else tries to + * use it */ + err = channel_disconnect(card,dev); + }else{ + err = execute_delayed_cmd(card, dev, + (mbox_cmd_t*)chan->common.mbox, + bad_cmd); + } + + switch (err){ + + case RETURN_RESULT: + + /* Return the result to the socket without + * delay. NO_WAIT Command */ + atomic_set(&chan->common.command,0); + if (atomic_read(&card->u.x.command_busy)) + atomic_set(&card->u.x.command_busy,0); + + send_delayed_cmd_result(card,dev,card->mbox); + + more_to_exec=0; + break; + case DELAY_RESULT: + + /* Wait for the remote to respond, before + * sending the result up to the socket. + * WAIT command */ + if (atomic_read(&card->u.x.command_busy)) + atomic_set(&card->u.x.command_busy,0); + + atomic_set(&chan->common.command,0); + more_to_exec=0; + break; + default: + + /* If command could not be executed for + * some reason (i.e return code 0x33 busy) + * set the more_to_exec bit which will + * indicate that this command must be exectued + * again during next timer interrupt + */ + more_to_exec=1; + if (atomic_read(&card->u.x.command_busy) == 0) + atomic_set(&card->u.x.command_busy,1); + break; + } + + bad_cmd=0; + + /* If flags is set, there are no hdlc buffers, + * thus, wait for the next pass and try the + * same command again. Otherwise, start searching + * from next device on the next pass. + */ + if (!more_to_exec){ + dev = move_dev_to_next(card,dev); + } + break; + }else{ + /* This device has nothing to execute, + * go to next. + */ + if (atomic_read(&card->u.x.command_busy)) + atomic_set(&card->u.x.command_busy,0); + dev = move_dev_to_next(card,dev); + } + + if (++i == card->u.x.no_dev){ + if (!more_to_exec){ + DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", + card->devname); + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + } + break; + } + + } //End of FOR + + card->u.x.cmd_dev = dev; + + if (more_to_exec){ + /* If more commands are pending, do not turn off timer + * interrupt */ + return 1; + }else{ + /* No more commands, turn off timer interrupt */ + return 0; + } +} + +/*=============================================================== + * execute_delayed_cmd + * + * Execute an API command which was passed down from the + * sock. Sock is very limited in which commands it can + * execute. Wait and No Wait commands are supported. + * Place Call, Clear Call and Reset wait commands, where + * Accept Call is a no_wait command. + * + *===============================================================*/ + +static int execute_delayed_cmd (sdla_t* card, netdevice_t *dev, mbox_cmd_t *usr_cmd,char bad_cmd) +{ + TX25Mbox* mbox = card->mbox; + int err; + x25_channel_t *chan = dev->priv; + int delay=RETURN_RESULT; + + if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ + return TRY_CMD_AGAIN; + } + + /* This way a command is guaranteed to be executed for + * a specific lcn, the network interface is bound to. */ + usr_cmd->cmd.lcn = chan->common.lcn; + + + /* If channel is pvc, instead of place call + * run x25_channel configuration. If running LAPB HDLC + * enable communications. + */ + if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ + + if (card->u.x.LAPB_hdlc){ + DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); + connect(card); + set_chan_state(dev,WAN_CONNECTING); + return DELAY_RESULT; + }else{ + DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); + if (x25_get_chan_conf(card, chan) == CMD_OK){ + set_chan_state(dev, WAN_CONNECTED); + }else{ + set_chan_state(dev, WAN_DISCONNECTED); + } + return RETURN_RESULT; + } + } + + /* Copy the socket mbox command onto the board */ + + memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); + if (usr_cmd->cmd.length){ + memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); + } + + /* Check if command is bad. We need to copy the cmd into + * the buffer regardless since we return the, mbox to + * the user */ + if (bad_cmd){ + mbox->cmd.result=0x01; + return RETURN_RESULT; + } + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK && err != X25RES_NOT_READY) + x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); + + if (mbox->cmd.result == X25RES_NOT_READY){ + return TRY_CMD_AGAIN; + } + + switch (mbox->cmd.command){ + + case X25_PLACE_CALL: + + switch (mbox->cmd.result){ + + case CMD_OK: + + /* Check if Place call is a wait command or a + * no wait command */ + if (atomic_read(&chan->common.command) & 0x80) + delay=RETURN_RESULT; + else + delay=DELAY_RESULT; + + + DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", + card->devname,dev->name, mbox->cmd.lcn); + + bind_lcn_to_dev (card, dev, mbox->cmd.lcn); + set_chan_state(dev, WAN_CONNECTING); + break; + + + default: + delay=RETURN_RESULT; + set_chan_state(dev, WAN_DISCONNECTED); + break; + } + break; + + case X25_ACCEPT_CALL: + + switch (mbox->cmd.result){ + + case CMD_OK: + + DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", + card->devname,dev->name,mbox->cmd.lcn); + + bind_lcn_to_dev (card, dev, mbox->cmd.lcn); + + if (x25_get_chan_conf(card, chan) == CMD_OK){ + + set_chan_state(dev, WAN_CONNECTED); + delay=RETURN_RESULT; + + }else{ + if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ + /* if clear is successful, wait for clear confirm + */ + delay=DELAY_RESULT; + }else{ + /* Do not change the state here. If we fail + * the accept the return code is send up + *the stack, which will ether retry + * or clear the call + */ + DBG_PRINTK(KERN_INFO + "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", + card->devname); + delay=RETURN_RESULT; + } + } + break; + + + case X25RES_ASYNC_PACKET: + delay=TRY_CMD_AGAIN; + break; + + default: + DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); + if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ + delay=DELAY_RESULT; + }else{ + /* Do not change the state here. If we fail the accept. The + * return code is send up the stack, which will ether retry + * or clear the call */ + DBG_PRINTK(KERN_INFO + "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", + card->devname); + delay=RETURN_RESULT; + } + } + break; + + case X25_CLEAR_CALL: + + switch (mbox->cmd.result){ + + case CMD_OK: + DBG_PRINTK(KERN_INFO + "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", + dev->name,mbox->cmd.lcn,chan->common.lcn); + set_chan_state(dev, WAN_DISCONNECTING); + delay = DELAY_RESULT; + break; + + case X25RES_CHANNEL_IN_USE: + case X25RES_ASYNC_PACKET: + delay = TRY_CMD_AGAIN; + break; + + case X25RES_LINK_NOT_IN_ABM: + case X25RES_INVAL_LCN: + case X25RES_INVAL_STATE: + set_chan_state(dev, WAN_DISCONNECTED); + delay = RETURN_RESULT; + break; + + default: + /* If command did not execute because of user + * fault, do not change the state. This will + * signal the socket that clear command failed. + * User can retry or close the socket. + * When socket gets killed, it will set the + * chan->disconnect which will signal + * driver to clear the call */ + printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", + card->devname,mbox->cmd.command); + delay = RETURN_RESULT; + } + break; + } + + return delay; +} + +/*=============================================================== + * api_incoming_call + * + * Pass an incoming call request up the the listening + * sock. If the API sock is not listening reject the + * call. + * + *===============================================================*/ + +static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) +{ + struct sk_buff *skb; + int len = sizeof(TX25Cmd)+mbox->cmd.length; + + if (alloc_and_init_skb_buf(card, &skb, len)){ + printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); + return 1; + } + + memcpy(skb_put(skb,len),&mbox->cmd,len); + + skb->mac.raw = skb->data; + skb->protocol = htons(X25_PROT); + skb->pkt_type = WAN_PACKET_ASYNC; + + if (card->func(skb,card->sk) < 0){ + printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); + wan_dev_kfree_skb(skb, FREE_READ); + return 1; + } + + return 0; +} + +/*=============================================================== + * send_delayed_cmd_result + * + * Wait commands like PLEACE CALL or CLEAR CALL must wait + * untill the result arrivers. This function passes + * the result to a waiting sock. + * + *===============================================================*/ +static void send_delayed_cmd_result(sdla_t *card, netdevice_t *dev, TX25Mbox* mbox) +{ + x25_channel_t *chan = dev->priv; + mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; + struct sk_buff *skb; + int len=sizeof(unsigned char); + + atomic_set(&chan->common.command,0); + + /* If the sock is in the process of unlinking the + * driver from the socket, we must get out. + * This never happends but is a sanity check. */ + if (test_bit(0,&chan->common.common_critical)){ + return; + } + + if (!usr_cmd || !chan->common.sk || !chan->common.func){ + DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", + (unsigned int)chan->common.sk, + (unsigned int)chan->common.func, + (unsigned int)usr_cmd); + return; + } + + memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); + if (mbox->cmd.length > 0){ + memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); + } + + if (alloc_and_init_skb_buf(card,&skb,len)){ + printk(KERN_INFO "Delay result: No sock buffers\n"); + return; + } + + memcpy(skb_put(skb,len),&mbox->cmd.command,len); + + skb->mac.raw = skb->data; + skb->pkt_type = WAN_PACKET_CMD; + + chan->common.func(skb,dev,chan->common.sk); +} + +/*=============================================================== + * clear_confirm_event + * + * Pass the clear confirmation event up the sock. The + * API will disconnect only after the clear confirmation + * has been received. + * + * Depending on the state, clear confirmation could + * be an OOB event, or a result of an API command. + *===============================================================*/ + +static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) +{ + netdevice_t *dev; + x25_channel_t *chan; + unsigned char old_state; + + dev = find_channel(card,mb->cmd.lcn); + if (!dev){ + DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", + card->devname,mb->cmd.lcn); + return 0; + } + + chan=dev->priv; + DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", + card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); + + /* If not API fall through to default. + * If API, send the result to a waiting + * socket. + */ + + old_state = chan->common.state; + set_chan_state(dev, WAN_DISCONNECTED); + + if (chan->common.usedby == API){ + switch (old_state) { + + case WAN_DISCONNECTING: + case WAN_CONNECTING: + send_delayed_cmd_result(card,dev,mb); + break; + case WAN_CONNECTED: + send_oob_msg(card,dev,mb); + break; + } + return 1; + } + + return 0; +} + +/*=============================================================== + * send_oob_msg + * + * Construct an NEM Message and pass it up the connected + * sock. If the sock is not bounded discard the NEM. + * + *===============================================================*/ + +static void send_oob_msg (sdla_t *card, netdevice_t *dev, TX25Mbox *mbox) +{ + x25_channel_t *chan = dev->priv; + mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; + struct sk_buff *skb; + int len=sizeof(x25api_hdr_t)+mbox->cmd.length; + x25api_t *api_hdr; + + /* If the sock is in the process of unlinking the + * driver from the socket, we must get out. + * This never happends but is a sanity check. */ + if (test_bit(0,&chan->common.common_critical)){ + return; + } + + if (!usr_cmd || !chan->common.sk || !chan->common.func){ + DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); + return; + } + + memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); + if (mbox->cmd.length > 0){ + memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); + } + + if (alloc_and_init_skb_buf(card,&skb,len)){ + printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); + return; + } + + api_hdr = (x25api_t*)skb_put(skb,len); + api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; + api_hdr->hdr.qdm = mbox->cmd.qdm; + api_hdr->hdr.cause = mbox->cmd.cause; + api_hdr->hdr.diagn = mbox->cmd.diagn; + api_hdr->hdr.length = mbox->cmd.length; + api_hdr->hdr.result = mbox->cmd.result; + api_hdr->hdr.lcn = mbox->cmd.lcn; + + if (mbox->cmd.length > 0){ + memcpy(api_hdr->data,mbox->data,mbox->cmd.length); + } + + skb->mac.raw = skb->data; + skb->pkt_type = WAN_PACKET_ERR; + + if (chan->common.func(skb,dev,chan->common.sk) < 0){ + if (bh_enqueue(dev,skb)){ + printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); + wan_dev_kfree_skb(skb, FREE_READ); + } + } + + DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", + card->devname, dev->name, mbox->cmd.lcn); +} + +/*=============================================================== + * alloc_and_init_skb_buf + * + * Allocate and initialize an skb buffer. + * + *===============================================================*/ + +static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) +{ + struct sk_buff *new_skb = *skb; + + new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + return 1; + } + + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_dev_kfree_skb(new_skb, FREE_READ); + printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" + ,card->devname); + *skb = NULL; + return 1; + } + + *skb = new_skb; + return 0; + +} + +/*=============================================================== + * api_oob_event + * + * Send an OOB event up to the sock + * + *===============================================================*/ + +static void api_oob_event (sdla_t *card,TX25Mbox *mbox) +{ + netdevice_t *dev = find_channel(card,mbox->cmd.lcn); + x25_channel_t *chan; + + if (!dev) + return; + + chan=dev->priv; + + if (chan->common.usedby == API) + send_oob_msg(card,dev,mbox); + +} + + + + +static int channel_disconnect (sdla_t* card, netdevice_t *dev) +{ + + int err; + x25_channel_t *chan = dev->priv; + + DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", + card->devname,dev->name); + + if (chan->common.svc){ + err = x25_clear_call(card,chan->common.lcn,0,0); + }else{ + /* If channel is PVC or LAPB HDLC, there is no call + * to be cleared, thus drop down to the default + * area + */ + err = 1; + } + + switch (err){ + + case X25RES_CHANNEL_IN_USE: + case X25RES_NOT_READY: + err = TRY_CMD_AGAIN; + break; + case CMD_OK: + DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", + dev->name,chan->common.lcn); + + set_chan_state(dev,WAN_DISCONNECTING); + atomic_set(&chan->common.command,0); + err = DELAY_RESULT; + break; + default: + /* If LAPB HDLC protocol, bring the whole link down + * once the application terminates + */ + + set_chan_state(dev,WAN_DISCONNECTED); + + if (card->u.x.LAPB_hdlc){ + DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); + hdlc_link_down (card); + } + atomic_set(&chan->common.command,0); + err = RETURN_RESULT; + break; + } + + return err; +} + +static void hdlc_link_down (sdla_t *card) +{ + TX25Mbox* mbox = card->mbox; + int retry = 5; + int err=0; + + do { + memset(mbox,0,sizeof(TX25Mbox)); + mbox->cmd.command = X25_HDLC_LINK_DISC; + mbox->cmd.length = 1; + mbox->data[0]=0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); + + if (err) + printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); + + disconnect (card); + +} + +static int check_bad_command (sdla_t* card, netdevice_t *dev) +{ + x25_channel_t *chan = dev->priv; + int bad_cmd = 0; + + switch (atomic_read(&chan->common.command)&0x7F){ + + case X25_PLACE_CALL: + if (chan->common.state != WAN_DISCONNECTED) + bad_cmd=1; + break; + case X25_CLEAR_CALL: + if (chan->common.state == WAN_DISCONNECTED) + bad_cmd=1; + break; + case X25_ACCEPT_CALL: + if (chan->common.state != WAN_CONNECTING) + bad_cmd=1; + break; + case X25_RESET: + if (chan->common.state != WAN_CONNECTED) + bad_cmd=1; + break; + default: + bad_cmd=1; + break; + } + + if (bad_cmd){ + printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", + card->devname,atomic_read(&chan->common.command),dev->name, + chan->common.lcn, chan->common.state); + } + + return bad_cmd; +} + + + +/*************************** XPIPEMON FUNCTIONS **************************/ + +/*============================================================================== + * Process UDP call of type XPIPE + */ + +static int process_udp_mgmt_pkt(sdla_t *card) +{ + int c_retry = MAX_CMD_RETRY; + unsigned int len; + struct sk_buff *new_skb; + TX25Mbox *mbox = card->mbox; + int err; + int udp_mgmt_req_valid = 1; + netdevice_t *dev; + x25_channel_t *chan; + unsigned short lcn; + struct timeval tv; + + + x25_udp_pkt_t *x25_udp_pkt; + x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; + + dev = card->u.x.udp_dev; + chan = dev->priv; + lcn = chan->common.lcn; + + switch(x25_udp_pkt->cblock.command) { + + /* XPIPE_ENABLE_TRACE */ + case XPIPE_ENABLE_TRACING: + + /* XPIPE_GET_TRACE_INFO */ + case XPIPE_GET_TRACE_INFO: + + /* SET FT1 MODE */ + case XPIPE_SET_FT1_MODE: + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + break; + } + + /* XPIPE_FT1_READ_STATUS */ + case XPIPE_FT1_READ_STATUS: + + /* FT1 MONITOR STATUS */ + case XPIPE_FT1_STATUS_CTRL: + if(card->hw.fwid != SFID_X25_508) { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; + udp_mgmt_req_valid = 0; + break; + } + default: + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + x25_udp_pkt->cblock.length = 0; + /* set return code */ + x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; + + } else { + + switch (x25_udp_pkt->cblock.command) { + + + case XPIPE_FLUSH_DRIVER_STATS: + init_x25_channel_struct(chan); + init_global_statistics(card); + mbox->cmd.length = 0; + break; + + + case XPIPE_DRIVER_STAT_IFSEND: + memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); + mbox->cmd.length = sizeof(if_send_stat_t); + x25_udp_pkt->cblock.length = mbox->cmd.length; + break; + + case XPIPE_DRIVER_STAT_INTR: + memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); + memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], + &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); + + mbox->cmd.length = sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + x25_udp_pkt->cblock.length = mbox->cmd.length; + break; + + case XPIPE_DRIVER_STAT_GEN: + memcpy(x25_udp_pkt->data, + &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + x25_udp_pkt->cblock.result = 0; + x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->cmd.length = x25_udp_pkt->cblock.length; + break; + + case XPIPE_ROUTER_UP_TIME: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - chan->router_start_time; + *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; + x25_udp_pkt->cblock.length = mbox->cmd.length = 4; + x25_udp_pkt->cblock.result = 0; + break; + + default : + + do { + memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); + if(mbox->cmd.length){ + memcpy(&mbox->data, + (char *)x25_udp_pkt->data, + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); + + + if ( err == CMD_OK || + (err == 1 && + (mbox->cmd.command == 0x06 || + mbox->cmd.command == 0x16) ) ){ + + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; + } + + /* copy the result back to our buffer */ + memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); + + if(mbox->cmd.length) { + memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); + } + break; + + } //switch + + } + + /* Fill UDP TTL */ + + x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); + + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); + if (!err) + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; + else + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; + + } else { + + /* Allocate socket buffer */ + if((new_skb = dev_alloc_skb(len)) != NULL) { + void *buf; + + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, card->u.x.udp_pkt_data, len); + + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->dev = dev; + + if (chan->common.usedby == API) + new_skb->protocol = htons(X25_PROT); + else + new_skb->protocol = htons(ETH_P_IP); + + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; + + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + card->u.x.udp_pkt_lgth = 0; + + return 1; +} + + +/*============================================================================== + * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) +{ + x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; + + if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && + (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && + (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + + if(!strncmp(x25_udp_pkt->wp_mgmt.signature, + UDPMGMT_XPIPE_SIGNATURE, 8)){ + return UDP_XPIPE_TYPE; + }else{ + printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", + card->devname); + } + } + + return UDP_INVALID_TYPE; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + + + x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + + /* fill in UDP reply */ + x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + x25_udp_pkt->udp_pkt.udp_length = temp; + + /* swap UDP ports */ + temp = x25_udp_pkt->udp_pkt.udp_src_port; + x25_udp_pkt->udp_pkt.udp_src_port = + x25_udp_pkt->udp_pkt.udp_dst_port; + x25_udp_pkt->udp_pkt.udp_dst_port = temp; + + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *) + (x25_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + x25_udp_pkt->udp_pkt.udp_checksum = 0; + + x25_udp_pkt->udp_pkt.udp_checksum = + calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + x25_udp_pkt->ip_pkt.total_length = temp; + + /* swap IP addresses */ + ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; + x25_udp_pkt->ip_pkt.ip_src_address = + x25_udp_pkt->ip_pkt.ip_dst_address; + x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + + + /* fill in IP checksum */ + x25_udp_pkt->ip_pkt.hdr_checksum = 0; + x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); + + return len; +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + netdevice_t *dev, struct sk_buff *skb, int lcn) +{ + int udp_pkt_stored = 0; + + if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ + card->u.x.udp_pkt_lgth = skb->len; + card->u.x.udp_type = udp_type; + card->u.x.udp_pkt_src = udp_pkt_src; + card->u.x.udp_lcn = lcn; + card->u.x.udp_dev = dev; + memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; + udp_pkt_stored = 1; + + }else{ + printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", + card->devname,lcn); + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + + return(udp_pkt_stored); +} + + + +/*============================================================================= + * Initial the ppp_private_area structure. + */ +static void init_x25_channel_struct( x25_channel_t *chan ) +{ + memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); + memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); + memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================ + * Initialize Global Statistics + */ +static void init_global_statistics( sdla_t *card ) +{ + memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); +} + + +/*=============================================================== + * SMP Support + * ==============================================================*/ + +static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); +} +static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +/*=============================================================== + * x25_timer_routine + * + * A more efficient polling routine. Each half a second + * queue a polling task. We want to do the polling in a + * task not timer, because timer runs in interrupt time. + * + * FIXME Polling should be rethinked. + *==============================================================*/ + +static void x25_timer_routine(unsigned long data) +{ + sdla_t *card = (sdla_t*)data; + + if (!card->wandev.dev){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", + card->devname); + return; + } + + if (card->open_cnt != card->u.x.num_of_ch){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", + card->devname); + return; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", + card->devname); + return; + } + + if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + trigger_x25_poll(card); + } + + card->u.x.x25_timer.expires=jiffies+(HZ>>1); + add_timer(&card->u.x.x25_timer); + return; +} + +void disable_comm_shutdown(sdla_t *card) +{ + TX25Mbox* mbox = card->mbox; + int err; + + /* Turn of interrutps */ + mbox->data[0] = 0; + if (card->hw.fwid == SFID_X25_508){ + mbox->data[1] = card->hw.irq; + mbox->data[2] = 2; + mbox->cmd.length = 3; + }else { + mbox->cmd.length = 1; + } + mbox->cmd.command = X25_SET_INTERRUPT_MODE; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); + + /* Bring down HDLC */ + mbox->cmd.command = X25_HDLC_LINK_CLOSE; + mbox->cmd.length = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); + + + /* Brind down DTR */ + mbox->data[0] = 0; + mbox->data[2] = 0; + mbox->data[1] = 0x01; + mbox->cmd.length = 3; + mbox->cmd.command = X25_SET_GLOBAL_VARS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + printk(KERN_INFO "DTR DOWN FAILED %x\n",err); + +} /****** End *****************************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c --- v2.4.3/linux/drivers/net/wan/sdladrv.c Tue Mar 6 19:44:37 2001 +++ linux/drivers/net/wan/sdladrv.c Thu Apr 12 12:11:39 2001 @@ -6,13 +6,19 @@ * * Author: Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * 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. * ============================================================================ +* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support +* the PCISLOT #0. +* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. +* The memory test at address 0xC8000. +* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci +* interrupt flags on initial load. * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. * Updates for Linux 2.2.X kernels. * Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels @@ -84,7 +90,6 @@ #if defined(_LINUX_) /****** Linux *******************************/ -#include <linux/config.h> #include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ @@ -102,7 +107,16 @@ #define _OUTB(port, byte) (outb((byte),(port))) #define SYSTEM_TICK jiffies -#include <linux/init.h> + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <linux/init.h> +#else + #include <linux/bios32.h>/* BIOS32, PCI BIOS functions and definitions */ + #define ioremap vremap + #define iounmap vfree + extern void * vremap (unsigned long offset, unsigned long size); + extern void vfree (void *addr); +#endif #elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ @@ -190,16 +204,21 @@ static unsigned check_memregion (void* ptr, unsigned len); static unsigned test_memregion (void* ptr, unsigned len); static unsigned short checksum (unsigned char* buf, unsigned len); +static int init_pci_slot(sdlahw_t *); + +static int pci_probe(sdlahw_t *hw); /****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! */ +#ifdef LINUX_2_4 static struct pci_device_id sdladrv_pci_tbl[] __initdata = { { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); +#endif /* private data */ static char modname[] = "sdladrv"; @@ -298,6 +317,8 @@ 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 }; +static int pci_slot_ar[MAX_S514_CARDS]; + /******* Kernel Loadable Module Entry Points ********************************/ /*============================================================================ @@ -314,15 +335,24 @@ #ifdef MODULE int init_module (void) #else -int __init wanpipe_init(void) +int sdladrv_init(void) #endif { + int i=0; + printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE, copyright); exec_idle = calibrate_delay(EXEC_DELAY); #ifdef WANDEBUG printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); #endif + + /* Initialize the PCI Card array, which + * will store flags, used to mark + * card initialization state */ + for (i=0; i<MAX_S514_CARDS; i++) + pci_slot_ar[i] = 0xFF; + return 0; } @@ -350,7 +380,9 @@ * < 0 error */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_setup); +#endif int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) { @@ -361,7 +393,7 @@ if (sdla_detect(hw)) { if(hw->type != SDLA_S514) - printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n", + printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", modname, hw->port); return -EINVAL; } @@ -410,7 +442,7 @@ /* Verify IRQ configuration options */ if (!get_option_index(irq_opt, hw->irq)) { - printk(KERN_ERR "%s: IRQ %d is illegal!\n", + printk(KERN_INFO "%s: IRQ %d is illegal!\n", modname, hw->irq); return -EINVAL; } @@ -420,7 +452,7 @@ hw->pclk = pclk_opt[1]; /* use default */ else if (!get_option_index(pclk_opt, hw->pclk)) { - printk(KERN_ERR "%s: CPU clock %u is illegal!\n", + printk(KERN_INFO "%s: CPU clock %u is illegal!\n", modname, hw->pclk); return -EINVAL; } @@ -431,7 +463,7 @@ if (hw->dpmbase == 0) { err = sdla_autodpm(hw); if (err) { - printk(KERN_ERR + printk(KERN_INFO "%s: can't find available memory region!\n", modname); return err; @@ -439,13 +471,13 @@ } else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase))) { - printk(KERN_ERR + printk(KERN_INFO "%s: memory address 0x%lX is illegal!\n", modname, virt_to_phys(hw->dpmbase)); return -EINVAL; } else if (sdla_setdpm(hw)) { - printk(KERN_ERR + printk(KERN_INFO "%s: 8K memory region at 0x%lX is not available!\n", modname, virt_to_phys(hw->dpmbase)); return -EINVAL; @@ -453,13 +485,27 @@ printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", modname, virt_to_phys(hw->dpmbase)); + + + /* If we find memory in 0xE**** Memory region, + * warn the user to disable the SHADOW RAM. + * Since memory corruption can occur if SHADOW is + * enabled. This can causes random crashes ! */ + if (virt_to_phys(hw->dpmbase) >= 0xE0000){ + printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); + printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", + modname, virt_to_phys(hw->dpmbase)); + printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); + printk(KERN_WARNING " your system might crash randomly from time to time !\n"); + printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); + } } else { hw->memory = test_memregion((void*)hw->dpmbase, MAX_SIZEOF_S514_MEMORY); if(hw->memory < (256 * 1024)) { - printk(KERN_ERR + printk(KERN_INFO "%s: error in testing S514 memory (0x%lX)\n", modname, hw->memory); sdla_down(hw); @@ -481,7 +527,9 @@ * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_down); +#endif int sdla_down (sdlahw_t* hw) { @@ -523,9 +571,10 @@ *(char *)hw->vector = S514_CPU_HALT; CPU_no = hw->S514_cpu_no[0]; +#if defined(LINUX_2_1) || defined(LINUX_2_4) /* disable the PCI IRQ and disable memory access */ pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); - int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; + int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); read_S514_int_stat(hw, &int_status); S514_intack(hw, int_status); @@ -535,6 +584,22 @@ else pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE); +#else + /* disable the PCI IRQ and disable memory access */ + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_CONFIG, &int_config); + int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_CONFIG, int_config); + read_S514_int_stat(hw, &int_status); + S514_intack(hw, int_status); + // disable PCI memory access + if(CPU_no == S514_CPU_A) + pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func, + PCI_MAP0_DWORD, PCI_CPU_A_MEM_DISABLE); + else + pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func, PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE); +#endif /* free up the allocated virtual memory */ iounmap((void *)hw->dpmbase); @@ -552,7 +617,9 @@ * Map shared memory window into SDLA address space. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_mapmem); +#endif int sdla_mapmem (sdlahw_t* hw, unsigned long addr) { @@ -613,7 +680,9 @@ * Enable interrupt generation. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_inten); +#endif int sdla_inten (sdlahw_t* hw) { @@ -669,7 +738,9 @@ * Disable interrupt generation. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_intde); +#endif int sdla_intde (sdlahw_t* hw) { @@ -724,7 +795,9 @@ * Acknowledge SDLA hardware interrupt. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_intack); +#endif int sdla_intack (sdlahw_t* hw) { @@ -774,11 +847,18 @@ * Acknowledge S514 hardware interrupt. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(S514_intack); +#endif void S514_intack (sdlahw_t* hw, u32 int_status) { +#if defined(LINUX_2_1) || defined(LINUX_2_4) pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); +#else + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_STATUS, int_status); +#endif } @@ -786,11 +866,18 @@ * Read the S514 hardware interrupt status. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(read_S514_int_stat); +#endif void read_S514_int_stat (sdlahw_t* hw, u32* int_status) { +#if defined(LINUX_2_1) || defined(LINUX_2_4) pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); +#else + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_STATUS, + int_status); +#endif } @@ -798,7 +885,9 @@ * Generate an interrupt to adapter's CPU. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_intr); +#endif int sdla_intr (sdlahw_t* hw) { @@ -842,7 +931,9 @@ * o Return number of loops made, or 0 if command timed out. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_exec); +#endif int sdla_exec (void* opflag) { @@ -878,7 +969,9 @@ * interrupt routines are accessing adapter shared memory. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_peek); +#endif int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) { @@ -960,7 +1053,9 @@ * interrupt routines are accessing adapter shared memory. */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) EXPORT_SYMBOL(sdla_poke); +#endif int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) { @@ -1124,7 +1219,11 @@ return -EINVAL; } - for (i = opt[0]; i && err; --i) { + /* Start testing from 8th position, address + * 0xC8000 from the 508 address table. + * We don't want to test A**** addresses, since + * they are usually used for Video */ + for (i = 8; i <= opt[0] && err; i++) { hw->dpmbase = phys_to_virt(opt[i]); err = sdla_setdpm(hw); } @@ -1176,14 +1275,14 @@ /* Verify firmware signature */ if (strcmp(sfm->signature, SFM_SIGNATURE)) { - printk(KERN_ERR "%s: not SDLA firmware!\n", + printk(KERN_INFO "%s: not SDLA firmware!\n", modname); return -EINVAL; } /* Verify firmware module format version */ if (sfm->version != SFM_VERSION) { - printk(KERN_ERR + printk(KERN_INFO "%s: firmware format %u rejected! Expecting %u.\n", modname, sfm->version, SFM_VERSION); return -EINVAL; @@ -1193,7 +1292,7 @@ if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || (checksum((void*)&sfm->info, sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { - printk(KERN_ERR "%s: firmware corrupted!\n", modname); + printk(KERN_INFO "%s: firmware corrupted!\n", modname); return -EINVAL; } @@ -1211,19 +1310,18 @@ */ for (i = 0; (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); - ++i) - ; + ++i); + if (i == SFM_MAX_SDLA) { - printk(KERN_ERR "%s: firmware is not compatible with S%u!\n", + printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", modname, hw->type); - ; return -EINVAL; } /* Make sure there is enough on-board memory */ if (hw->memory < sfm->info.memsize) { - printk(KERN_ERR + printk(KERN_INFO "%s: firmware needs %lu bytes of on-board memory!\n", modname, sfm->info.memsize); return -EINVAL; @@ -1231,7 +1329,7 @@ /* Move code onto adapter */ if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { - printk(KERN_ERR "%s: failed to load code segment!\n", + printk(KERN_INFO "%s: failed to load code segment!\n", modname); return -EIO; } @@ -1239,14 +1337,14 @@ /* Prepare boot-time configuration data and kick-off CPU */ sdla_bootcfg(hw, &sfm->info); if (sdla_start(hw, sfm->info.startoffs)) { - printk(KERN_ERR "%s: Damn... Adapter won't start!\n", + printk(KERN_INFO "%s: Damn... Adapter won't start!\n", modname); return -EIO; } /* position DPM window over the mailbox and enable interrupts */ if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { - printk(KERN_ERR "%s: adapter hardware failure!\n", + printk(KERN_INFO "%s: adapter hardware failure!\n", modname); return -EIO; } @@ -1858,22 +1956,30 @@ */ static int detect_s514 (sdlahw_t* hw) { - unsigned char CPU_no, slot_no; + unsigned char CPU_no, slot_no, auto_slot_cfg; int number_S514_cards = 0; u32 S514_mem_base_addr = 0; u32 ut_u32; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct pci_dev *pci_dev; +#else + u8 ut_u8; +#endif #ifdef CONFIG_PCI +#if defined(LINUX_2_1) || defined(LINUX_2_4) if(!pci_present()) +#else + if(!pcibios_present()) +#endif { - printk(KERN_ERR "%s: PCI BIOS not present!\n", modname); + printk(KERN_INFO "%s: PCI BIOS not present!\n", modname); return 0; } #else - printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname); + printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); return 0; #endif @@ -1883,10 +1989,17 @@ */ CPU_no = hw->S514_cpu_no[0]; slot_no = hw->S514_slot_no; - - printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n", - modname, CPU_no, slot_no); + auto_slot_cfg = hw->auto_pci_cfg; + if (auto_slot_cfg){ + printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", + modname, CPU_no); + + }else{ + printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", + modname, CPU_no, slot_no); + } + /* check to see that CPU A or B has been selected in 'router.conf' */ switch(CPU_no) { case S514_CPU_A: @@ -1894,9 +2007,9 @@ break; default: - printk(KERN_ERR "%s: S514 CPU definition invalid.\n", + printk(KERN_INFO "%s: S514 CPU definition invalid.\n", modname); - printk(KERN_ERR "Must be 'A' or 'B'\n"); + printk(KERN_INFO "Must be 'A' or 'B'\n"); return 0; } @@ -1904,50 +2017,110 @@ if(!number_S514_cards) return 0; - /* we are using a single S514 adapter with a slot of 0 so re-read the */ /* location of this adapter */ - if((number_S514_cards == 1) && !slot_no) { + /* we are using a single S514 adapter with a slot of 0 so re-read the */ + /* location of this adapter */ + if((number_S514_cards == 1) && auto_slot_cfg) { number_S514_cards = find_s514_adapter(hw, 1); if(!number_S514_cards) { - printk(KERN_ERR "%s: Error finding PCI card\n", + printk(KERN_INFO "%s: Error finding PCI card\n", modname); return 0; } } + #if defined(LINUX_2_4) pci_dev = hw->pci_dev; /* read the physical memory base address */ S514_mem_base_addr = (CPU_no == S514_CPU_A) ? (pci_dev->resource[1].start) : (pci_dev->resource[2].start); + + #elif defined (LINUX_2_1) + pci_dev = hw->pci_dev; + /* read the physical memory base address */ + S514_mem_base_addr = (CPU_no == S514_CPU_A) ? + (pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK) : + (pci_dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK); + + #else + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, + (CPU_no == S514_CPU_A) ? PCI_MEM_BASE0_DWORD : + PCI_MEM_BASE1_DWORD, &S514_mem_base_addr); + #endif printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", modname, S514_mem_base_addr); if(!S514_mem_base_addr) { if(CPU_no == S514_CPU_B) - printk(KERN_ERR "%s: CPU #B not present on the card\n", modname); + printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); else - printk(KERN_ERR "%s: No PCI memory allocated to card\n", modname); + printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); return 0; } /* enable the PCI memory */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) pci_read_config_dword(pci_dev, (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, &ut_u32); pci_write_config_dword(pci_dev, (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, (ut_u32 | PCI_MEMORY_ENABLE)); +#else + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, + (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + &ut_u32); + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + (ut_u32 | PCI_MEMORY_ENABLE)); +#endif /* check the IRQ allocated and enable IRQ usage */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) if(!(hw->irq = pci_dev->irq)) { - printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n", + printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", modname); return 0; } + + /* BUG FIX : Mar 6 2000 + * On a initial loading of the card, we must check + * and clear PCI interrupt bits, due to a reset + * problem on some other boards. i.e. An interrupt + * might be pending, even after system bootup, + * in which case, when starting wanrouter the machine + * would crash. + */ + if (init_pci_slot(hw)) + return 0; + pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); ut_u32 |= (CPU_no == S514_CPU_A) ? PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); +#else + /* the INTPIN must not be 0 - if it is, then the S514 adapter is not */ + /* configured for IRQ usage */ + pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func, + PCI_INT_PIN_BYTE, &ut_u8); + if(!ut_u8) { + printk(KERN_INFO "%s: invalid setting for INTPIN on S514 card\n", modname); + printk(KERN_INFO "Please contact your Sangoma representative\n"); + return 0; + } + pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func, + PCI_INT_LINE_BYTE, (unsigned char *)&hw->irq); + if(hw->irq == PCI_IRQ_NOT_ALLOCATED) { + printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", + modname); + return 0; + } + pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_CONFIG, &ut_u32); + ut_u32 |= (CPU_no == S514_CPU_A) ? + PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; + pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, + PCI_INT_CONFIG, ut_u32); +#endif printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", modname, hw->irq); @@ -1961,7 +2134,7 @@ (unsigned long)16); if(!hw->dpmbase || !hw->vector) { - printk(KERN_ERR "%s: PCI virtual memory allocation failed\n", + printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", modname); return 0; } @@ -1983,49 +2156,99 @@ char S514_found_in_slot = 0; u16 PCI_subsys_vendor; +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct pci_dev *pci_dev = NULL; +#else + int pci_index; +#endif slot_no = hw->S514_slot_no; +#if defined(LINUX_2_1) || defined(LINUX_2_4) while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) != NULL) { - if (pci_enable_device(pci_dev)) - continue; - PCI_subsys_vendor = pci_dev->subsystem_vendor; - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + + pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) continue; - hw->pci_dev = pci_dev; + + hw->pci_dev = pci_dev; + if(find_first_S514_card) return(1); + number_S514_cards ++; - printk(KERN_INFO + + printk(KERN_INFO "%s: S514 card found, slot #%d (devfn 0x%X)\n", modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), pci_dev->devfn); - if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == - slot_no)) { + + if (hw->auto_pci_cfg){ + hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); + slot_no = hw->S514_slot_no; + + }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ + S514_found_in_slot = 1; + break; + } + } + +#else + //LINUX VERSION 2.0.X + for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) { + if (pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index, + &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) { + break; + } + + pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func, + PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor); + + if (PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + if (find_first_S514_card) + return(1); + + number_S514_cards ++; + + printk(KERN_INFO "%s: S514 card found, bus #%d, slot #%d\n", + modname, hw->pci_bus, + ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK)); + + if (hw->auto_pci_cfg){ + hw->S514_slot_no = ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) + slot_no = hw->S514_slot_no; + + }else if (((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) == slot_no) { S514_found_in_slot = 1; break; } } +#endif /* if no S514 adapter has been found, then exit */ - if(!number_S514_cards) { - printk(KERN_ERR "%s: no S514 adapters found\n", modname); + if (!number_S514_cards) { + printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); return 0; } /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ - else if((number_S514_cards > 1) && !slot_no) { - printk(KERN_ERR "%s: More than one S514 adapter found\n", - modname); - printk(KERN_ERR "Define a PCI slot number for this adapter\n"); + else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { + printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" + "%s: More than one S514 adapter found.\n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCISLOT numbers for each card.\n", + modname,modname,modname,modname); return 0; } /* if the user has specified a slot number and the S514 adapter has */ /* not been found in that slot, then exit */ - else if (slot_no && !S514_found_in_slot) { - printk(KERN_ERR - "%s: S514 card not found in specified slot #%d\n", + else if (!hw->auto_pci_cfg && !S514_found_in_slot) { + printk(KERN_INFO + "%s: Error, S514 card not found in specified slot #%d\n", modname, slot_no); return 0; } @@ -2138,5 +2361,170 @@ return crc; } +static int init_pci_slot(sdlahw_t *hw) +{ + + u32 int_status; + int volatile found=0; + int i=0; + + /* Check if this is a very first load for a specific + * pci card. If it is, clear the interrput bits, and + * set the flag indicating that this card was initialized. + */ + + for (i=0; (i<MAX_S514_CARDS) && !found; i++){ + if (pci_slot_ar[i] == hw->S514_slot_no){ + found=1; + break; + } + if (pci_slot_ar[i] == 0xFF){ + break; + } + } + + if (!found){ + read_S514_int_stat(hw,&int_status); + S514_intack(hw,int_status); + if (i == MAX_S514_CARDS){ + printk(KERN_INFO "%s: Critical Error !!!\n",modname); + printk(KERN_INFO + "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", + modname); + printk(KERN_INFO "Please contact Sangoma Technologies\n"); + return 1; + } + pci_slot_ar[i] = hw->S514_slot_no; + } + return 0; +} + +static int pci_probe(sdlahw_t *hw) +{ + + unsigned char slot_no; + int number_S514_cards = 0; + u16 PCI_subsys_vendor; + u16 PCI_card_type; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + struct pci_dev *pci_dev = NULL; + struct pci_bus *bus = NULL; +#else + int pci_index; + u8 irq; +#endif + + slot_no = 0; + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) + != NULL) { + + pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + pci_read_config_word(pci_dev, PCI_CARD_TYPE, + &PCI_card_type); + + bus = pci_dev->bus; + + /* A dual cpu card can support up to 4 physical connections, + * where a single cpu card can support up to 2 physical + * connections. The FT1 card can only support a single + * connection, however we cannot distinguish between a Single + * CPU card and an FT1 card. */ + if (PCI_card_type == S514_DUAL_CPU){ + number_S514_cards += 4; + printk(KERN_INFO + "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->irq); + }else{ + number_S514_cards += 2; + printk(KERN_INFO + "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->irq); + } + } + +#else + for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) { + + if(pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index, + &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) { + break; + } + pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func, + PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor); + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + pcibios_read_config_word(hw->pci_bus,hw->pci_dev_func,PCI_CARD_TYPE, + &PCI_card_type); + + pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func, + PCI_INT_LINE_BYTE, &irq); + + /* A dual cpu card can support up to 4 physical connections, + * where a single cpu card can support up to 2 physical + * connections. The FT1 card can only support a single + * connection, however we cannot distinguish between a Single + * CPU card and an FT1 card. */ + if (PCI_card_type == S514_DUAL_CPU){ + number_S514_cards += 4; + printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + modname, hw->pci_bus, + ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq); + }else{ + printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + modname, hw->pci_bus, + ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq); + number_S514_cards += 2; + } + } +#endif + + return number_S514_cards; + +} + + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +EXPORT_SYMBOL(wanpipe_hw_probe); +#endif + +unsigned wanpipe_hw_probe(void) +{ + sdlahw_t hw; + unsigned* opt = s508_port_options; + unsigned cardno=0; + int i; + + memset(&hw, 0, sizeof(hw)); + + for (i = 1; i <= opt[0]; i++) { + if (detect_s508(opt[i])){ + /* S508 card can support up to two physical links */ + cardno+=2; + printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); + } + } + + #ifdef CONFIG_PCI + hw.S514_slot_no = 0; + cardno += pci_probe(&hw); + #else + printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); + printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); + #endif + + return cardno; +} /****** End *****************************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c --- v2.4.3/linux/drivers/net/wan/sdlamain.c Tue Mar 6 19:44:36 2001 +++ linux/drivers/net/wan/sdlamain.c Thu Apr 12 12:11:39 2001 @@ -1,16 +1,28 @@ -/***************************************************************************** +/**************************************************************************** * sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. * * Author: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * 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. * ============================================================================ +* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. +* Removed the polling routine. +* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic +* device allocation. +* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels +* 2.2.16 and above. +* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on +* kernels 2.2.16 or greater. The SyncPPP +* has changed. +* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. +* Jul 13, 2000 Nenad Corbic Added Multi-PPP support. +* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. * Sep 23, 1999 Nenad Corbic Added support for SMP * Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. @@ -39,17 +51,125 @@ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/module.h> /* support for loadable modules */ #include <linux/ioport.h> /* request_region(), release_region() */ -#include <linux/tqueue.h> /* for kernel task queues */ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <asm/uaccess.h> /* kernel <-> user copy */ + +#include <linux/in.h> #include <asm/io.h> /* phys_to_virt() */ #include <linux/pci.h> #include <linux/sdlapci.h> +#include <linux/if_wanpipe_common.h> + +#if defined(LINUX_2_4) + + #include <asm/uaccess.h> /* kernel <-> user copy */ + #include <linux/inetdevice.h> + #define netdevice_t struct net_device + +#elif defined(LINUX_2_1) + + #include <asm/uaccess.h> /* kernel <-> user copy */ + #include <linux/inetdevice.h> + #define netdevice_t struct device + +#else + + #include <asm/segment.h> + #define devinet_ioctl(x,y) dev_ioctl(x,y) + #define netdevice_t struct device + #define test_and_set_bit set_bit + typedef unsigned long mm_segment_t; +#endif + +#include <linux/ip.h> +#include <net/route.h> + +#define KMEM_SAFETYZONE 8 + + +#ifndef CONFIG_WANPIPE_FR + #define wpf_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_CHDLC + #define wpc_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_X25 + #define wpx_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_PPP + #define wpp_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_WANPIPE_MULTPPP + #define wsppp_init(a,b) (-EPROTONOSUPPORT) +#endif + + +/***********FOR DEBUGGING PURPOSES********************************************* +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +******************************************************************************/ + + /****** Defines & Macros ****************************************************/ @@ -61,7 +181,7 @@ #define DRV_VERSION 5 /* version number */ #define DRV_RELEASE 0 /* release (minor version) number */ -#define MAX_CARDS 8 /* max number of adapters */ +#define MAX_CARDS 16 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ #define CONFIG_WANPIPE_CARDS 1 @@ -86,12 +206,16 @@ /* IOCTL handlers */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec); +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); /* Miscellaneous functions */ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs); -STATIC void sdla_poll (void* data); static void release_hw (sdla_t *card); +static void run_wanpipe_tq (unsigned long); + +static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); +static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); + /****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! @@ -100,13 +224,41 @@ /* private data */ static char drvname[] = "wanpipe"; static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; -static int ncards = CONFIG_WANPIPE_CARDS; -static int active; /* number of active cards */ -static sdla_t* card_array; /* adapter data space */ +static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; +static int ncards = 0; +static sdla_t* card_array = NULL; /* adapter data space */ + +/* Wanpipe's own task queue, used for all API's. + * All protocol specific tasks will be instered + * into "wanpipe_tq_custom" task_queue. + + * On each rx_interrupt, the whole task queue + * (wanpipe_tq_custom) will be queued into + * IMMEDIATE_BH via wanpipe_mark_bh() call. + + * The IMMEDIATE_BH will execute run_wanpipe_tq() + * function, which will execute all pending, + * tasks in wanpipe_tq_custom queue */ + +#ifdef LINUX_2_4 +DECLARE_TASK_QUEUE(wanpipe_tq_custom); +static struct tq_struct wanpipe_tq_task = +{ + routine: (void (*)(void *)) run_wanpipe_tq, + data: &wanpipe_tq_custom +}; +#else +static struct tq_struct *wanpipe_tq_custom = NULL; +static struct tq_struct wanpipe_tq_task = +{ + NULL, + 0, + (void *)(void *) run_wanpipe_tq, + &wanpipe_tq_custom +}; +#endif -/* Task queue element for creating a 'thread' */ -static struct tq_struct sdla_tq = { routine: sdla_poll }; +static int wanpipe_bh_critical=0; /******* Kernel Loadable Module Entry Points ********************************/ @@ -126,7 +278,7 @@ #ifdef MODULE int init_module (void) #else -int wanpipe_init2(void) +int wanpipe_init(void) #endif { int cnt, err = 0; @@ -134,9 +286,17 @@ printk(KERN_INFO "%s v%u.%u %s\n", fullname, DRV_VERSION, DRV_RELEASE, copyright); + /* Probe for wanpipe cards and return the number found */ + printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); + ncards = wanpipe_hw_probe(); + if (ncards){ + printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); + }else{ + printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); + return -ENODEV; + } + /* Verify number of cards and allocate adapter data space */ - ncards = min(ncards, MAX_CARDS); - ncards = max(ncards, 1); card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); if (card_array == NULL) return -ENOMEM; @@ -159,7 +319,7 @@ wandev->ioctl = &ioctl; err = register_wan_device(wandev); if (err) { - printk(KERN_ERR + printk(KERN_INFO "%s: %s registration failed with error %d!\n", drvname, card->devname, err); break; @@ -172,6 +332,7 @@ printk(KERN_INFO "IN Init Module: NO Cards registered\n"); err = -ENODEV; } + return err; } @@ -185,11 +346,16 @@ { int i; + if (!ncards) + return; + for (i = 0; i < ncards; ++i) { sdla_t* card = &card_array[i]; unregister_wan_device(card->devname); } kfree(card_array); + + printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); } #endif @@ -218,15 +384,25 @@ sdla_t* card; int err = 0; int irq=0; - int i; /* Sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)) + if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ + printk(KERN_INFO + "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", + wandev->name, + (unsigned int)wandev,(unsigned int)wandev->private, + (unsigned int)conf); return -EFAULT; - + } + + printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); + card = wandev->private; - if (wandev->state != WAN_UNCONFIGURED) + if (wandev->state != WAN_UNCONFIGURED){ + printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", + wandev->name); return -EBUSY; /* already configured */ + } printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); @@ -239,84 +415,21 @@ wandev->config_id = conf->config_id; if (!conf->data_size || (conf->data == NULL)) { - printk(KERN_ERR + printk(KERN_INFO "%s: firmware not found in configuration data!\n", wandev->name); return -EINVAL; } - /* only check I/O port and IRQ if not an S514 adapter */ + /* Check for resource conflicts and setup the + * card for piggibacking if necessary */ if(!conf->S514_CPU_no[0]) { - - if (conf->ioport <= 0) { - printk(KERN_ERR - "%s: can't configure without I/O port address!\n", - wandev->name); - return -EINVAL; - } - - if (conf->irq <= 0) { - printk(KERN_ERR "%s: can't configure without IRQ!\n", - wandev->name); - return -EINVAL; - } - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - if (!card->configured){ - for (i = 0; i < ncards; i ++) { - sdla_t *nxt_card = &card_array[i]; - if (nxt_card->hw.port == conf->ioport && - nxt_card != card && - conf->config_id == WANCONFIG_CHDLC && - nxt_card->wandev.config_id == WANCONFIG_CHDLC){ - irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - nxt_card->next = card; - card->next = nxt_card; - card->wandev.piggyback = WANOPT_YES; - } - } - - - /* Make sure I/O port region is available */ - if (check_region(conf->ioport, SDLA_MAXIORANGE) && - !card->wandev.piggyback) { - printk(KERN_ERR - "%s: I/O region 0x%X - 0x%X is in use!\n", - wandev->name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE); - return -EINVAL; - } + if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ + return err; } - } - - /* - For a S514 adapter, check for a possible configuration error in that - we are loading an adapter in the same slot as a previously loaded S514 - card. - */ - else { - if (!card->configured){ - for (i = 0; i < ncards; i ++) { - sdla_t* nxt_card = &card_array[i]; - if(nxt_card == card) - continue; - if((nxt_card->hw.type == SDLA_S514) && - (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && - (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& - (conf->config_id == WANCONFIG_CHDLC)&& - (nxt_card->wandev.config_id == WANCONFIG_CHDLC)){ - - irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - nxt_card->next = card; - card->next = nxt_card; - card->wandev.piggyback = WANOPT_YES; - } - } + }else { + if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ + return err; } } @@ -336,8 +449,15 @@ card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; card->hw.S514_slot_no = conf->PCI_slot_no; - printk(KERN_INFO "Setting CPU to %c and Slot to %i\n", - card->hw.S514_cpu_no[0], card->hw.S514_slot_no); + card->hw.auto_pci_cfg = conf->auto_pci_cfg; + + if (card->hw.auto_pci_cfg == WANOPT_YES){ + printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", + card->devname, card->hw.S514_cpu_no[0]); + }else{ + printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", + card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); + } }else{ /* 508 Card io port and irq initialization */ @@ -347,18 +467,22 @@ /* Compute the virtual address of the card in kernel space */ - if(conf->maddr) + if(conf->maddr){ card->hw.dpmbase = phys_to_virt(conf->maddr); - else /* But 0 means NULL */ + }else{ card->hw.dpmbase = (void *)conf->maddr; - + } + card->hw.dpmsize = SDLA_WINDOWSIZE; + /* set the adapter type if using an S514 adapter */ card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; card->hw.pclk = conf->hw_opt[1]; err = sdla_setup(&card->hw, conf->data, conf->data_size); if (err){ + printk(KERN_INFO "%s: Hardware setup Failed %i\n", + card->devname,err); return err; } @@ -369,10 +493,12 @@ /* request an interrupt vector - note that interrupts may be shared */ /* when using the S514 PCI adapter */ + if(request_irq(irq, sdla_isr, - (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, wandev->name, card)){ + (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, + wandev->name, card)){ - printk(KERN_ERR "%s: Can't reserve IRQ %d!\n", wandev->name, irq); + printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); return -EINVAL; } @@ -384,11 +510,16 @@ if (!card->configured){ - #ifdef CONFIG_SMP /* Initialize the Spin lock */ - printk(KERN_INFO "%s: Initializing SMP\n",wandev->name); - spin_lock_init(&card->lock); - #endif + #if defined(__SMP__) || defined(LINUX_2_4) + printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); + #endif + + /* Piggiback spin lock has already been initialized, + * in check_s514/s508_conflicts() */ + if (!card->wandev.piggyback){ + spin_lock_init(&card->wandev.lock); + } /* Intialize WAN device data space */ wandev->irq = irq; @@ -409,63 +540,65 @@ /* Protocol-specific initialization */ switch (card->hw.fwid) { -#ifdef CONFIG_WANPIPE_X25 + case SFID_X25_502: case SFID_X25_508: + printk(KERN_INFO "%s: Starting x25 Protocol Init.\n", + card->devname); err = wpx_init(card, conf); break; -#endif - -#ifdef CONFIG_WANPIPE_FR case SFID_FR502: case SFID_FR508: + printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", + card->devname); err = wpf_init(card, conf); break; -#endif - -#ifdef CONFIG_WANPIPE_PPP case SFID_PPP502: case SFID_PPP508: + printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", + card->devname); err = wpp_init(card, conf); break; -#endif - -#ifdef CONFIG_WANPIPE_CHDLC + case SFID_CHDLC508: case SFID_CHDLC514: -// if (conf->ft1){ -// printk(KERN_INFO "%s: Starting FT1 Configurator\n", -// card->devname); -// err = wpft1_init(card, conf); -// }else{ - err = wpc_init(card, conf); -// } - break; -#endif - -#ifdef CONFIG_WANPIPE_BSTRM - case SFID_BSC502: - err = bsc_init(card, conf); - break; -#endif - -#ifdef CONFIG_WANPIPE_HDLC - case SFID_HDLC508: - err = hdlc_init(card, conf); - break; -#endif + if (conf->ft1){ + printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", + card->devname); + err = wpft1_init(card, conf); + break; + + }else if (conf->config_id == WANCONFIG_MPPP){ + printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", + card->devname); + err = wsppp_init(card,conf); + break; + }else{ + printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", + card->devname); + err = wpc_init(card, conf); + break; + } default: - printk(KERN_ERR "%s: this firmware is not supported %X %X!\n", + printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", wandev->name,card->hw.fwid,SFID_CHDLC508); - err = -EINVAL; + err = -EPROTONOSUPPORT; } - - if (err){ + if (err != 0){ + if (err == -EPROTONOSUPPORT){ + printk(KERN_INFO + "%s: Error, Protocol selected has not been compiled!\n", + card->devname); + printk(KERN_INFO + "%s: Re-configure the kernel and re-build the modules!\n", + card->devname); + } + release_hw(card); + wandev->state = WAN_UNCONFIGURED; return err; - } @@ -473,16 +606,194 @@ if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) request_region(card->hw.port, card->hw.io_range, wandev->name); - if (++active == 1) { - MOD_INC_USE_COUNT; - if (schedule_task(&sdla_tq) == 0) - MOD_DEC_USE_COUNT; + /* Only use the polling routine for the X25 protocol */ + + card->wandev.critical=0; + return 0; +} + +/*================================================================== + * configure_s508_card + * + * For a S508 adapter, check for a possible configuration error in that + * we are loading an adapter in the same IO port as a previously loaded S508 + * card. + */ + +static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) +{ + unsigned long smp_flags; + int i; + + if (conf->ioport <= 0) { + printk(KERN_INFO + "%s: can't configure without I/O port address!\n", + card->wandev.name); + return -EINVAL; + } + + if (conf->irq <= 0) { + printk(KERN_INFO "%s: can't configure without IRQ!\n", + card->wandev.name); + return -EINVAL; } + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (i = 0; i < ncards; i++) { + sdla_t *nxt_card = &card_array[i]; + + /* Skip the current card ptr */ + if (nxt_card == card) + continue; + + + /* Find a card that is already configured with the + * same IO Port */ + if ((nxt_card->hw.type == SDLA_S508) && + (nxt_card->hw.port == conf->ioport) && + (nxt_card->next == NULL)){ + + /* We found a card the card that has same configuration + * as us. This means, that we must setup this card in + * piggibacking mode. However, only CHDLC and MPPP protocol + * support this setup */ + + if ((conf->config_id == WANCONFIG_CHDLC || + conf->config_id == WANCONFIG_MPPP) && + (nxt_card->wandev.config_id == WANCONFIG_CHDLC || + nxt_card->wandev.config_id == WANCONFIG_MPPP)){ + + *irq = nxt_card->hw.irq; + memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); + + /* The master could already be running, we must + * set this as a critical area */ + lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); + + nxt_card->next = card; + card->next = nxt_card; + + card->wandev.piggyback = WANOPT_YES; + + /* We must initialise the piggiback spin lock here + * since isr will try to lock card->next if it + * exists */ + spin_lock_init(&card->wandev.lock); + + unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); + break; + }else{ + /* Trying to run piggibacking with a wrong protocol */ + printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname,nxt_card->hw.port, + card->devname,card->devname); + return -EEXIST; + } + } + } + + + /* Make sure I/O port region is available only if we are the + * master device. If we are running in piggibacking mode, + * we will use the resources of the master card */ + if (check_region(conf->ioport, SDLA_MAXIORANGE) && + !card->wandev.piggyback) { + printk(KERN_INFO + "%s: I/O region 0x%X - 0x%X is in use!\n", + card->wandev.name, conf->ioport, + conf->ioport + SDLA_MAXIORANGE); + return -EINVAL; + } + + return 0; +} + +/*================================================================== + * configure_s514_card + * + * For a S514 adapter, check for a possible configuration error in that + * we are loading an adapter in the same slot as a previously loaded S514 + * card. + */ + + +static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) +{ + unsigned long smp_flags; + int i; + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (i = 0; i < ncards; i ++) { + + sdla_t* nxt_card = &card_array[i]; + if(nxt_card == card) + continue; - wandev->critical = 0; + if((nxt_card->hw.type == SDLA_S514) && + (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && + (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& + (nxt_card->next == NULL)){ + + + if ((conf->config_id == WANCONFIG_CHDLC || + conf->config_id == WANCONFIG_MPPP) && + (nxt_card->wandev.config_id == WANCONFIG_CHDLC || + nxt_card->wandev.config_id == WANCONFIG_MPPP)){ + + *irq = nxt_card->hw.irq; + memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); + + /* The master could already be running, we must + * set this as a critical area */ + lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); + nxt_card->next = card; + card->next = nxt_card; + + card->wandev.piggyback = WANOPT_YES; + + /* We must initialise the piggiback spin lock here + * since isr will try to lock card->next if it + * exists */ + spin_lock_init(&card->wandev.lock); + + unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); + + }else{ + /* Trying to run piggibacking with a wrong protocol */ + printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname, + conf->S514_CPU_no[0],conf->PCI_slot_no, + card->devname,card->devname); + return -EEXIST; + } + } + } + return 0; } + + /*============================================================================ * Shut down WAN link driver. * o shut down adapter hardware @@ -494,23 +805,39 @@ static int shutdown (wan_device_t* wandev) { sdla_t *card; - + int err=0; + /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) + if ((wandev == NULL) || (wandev->private == NULL)){ return -EFAULT; + } - if (wandev->state == WAN_UNCONFIGURED) + if (wandev->state == WAN_UNCONFIGURED){ return 0; - - /* If we are in a critical section we lose */ - if (test_and_set_bit(0, (void*)&wandev->critical)) - return -EAGAIN; - + } + card = wandev->private; + + if (card->tty_opt){ + if (card->tty_open){ + printk(KERN_INFO + "%s: Shutdown Failed: TTY is still open\n", + card->devname); + return -EBUSY; + } + } + wandev->state = WAN_UNCONFIGURED; - if (--active == 0) - schedule(); /* stop background thread */ + set_bit(PERI_CRIT,(void*)&wandev->critical); + + /* In case of piggibacking, make sure that + * we never try to shutdown both devices at the same + * time, because they depend on one another */ + + if (card->disable_comm){ + card->disable_comm(card); + } /* Release Resources */ release_hw(card); @@ -526,15 +853,17 @@ memset(&card->next->hw, 0, sizeof(sdlahw_t)); } } + - wandev->critical = 0; - return 0; + clear_bit(PERI_CRIT,(void*)&wandev->critical); + return err; } static void release_hw (sdla_t *card) { sdla_t *nxt_card; + /* Check if next device exists */ if (card->next){ nxt_card = card->next; @@ -559,8 +888,9 @@ card->next->configured = 0; } }else{ - printk(KERN_INFO "%s: Device still running\n", - nxt_card->devname); + printk(KERN_INFO "%s: Device still running %i\n", + nxt_card->devname,nxt_card->wandev.state); + card->configured = 1; } }else{ @@ -569,6 +899,7 @@ free_irq(card->wandev.irq, card); card->configured = 0; } + return; } @@ -597,10 +928,7 @@ disable_irq(card->hw.irq); } - if (test_and_set_bit(0, (void*)&wandev->critical)) { - if(card->hw.type != SDLA_S514){ - enable_irq(card->hw.irq); - } + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { return -EAGAIN; } @@ -610,18 +938,12 @@ break; case WANPIPE_EXEC: - err = ioctl_exec(wandev->private, (void*)arg); + err = ioctl_exec(wandev->private, (void*)arg, cmd); break; - default: err = -EINVAL; } - clear_bit(0, (void*)&wandev->critical); - if(card->hw.type != SDLA_S514){ - enable_irq(card->hw.irq); - } - return err; } @@ -635,7 +957,7 @@ * o verify user buffer * o copy adapter memory image to user buffer * - * Note: when dumping memory, this routine switches current dual-port memory + * Note: when dumping memory, this routine switches curent dual-port memory * vector, so care must be taken to avoid racing conditions. */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) @@ -643,21 +965,35 @@ sdla_dump_t dump; unsigned winsize; unsigned long oldvec; /* DPM window vector */ - unsigned long flags; + unsigned long smp_flags; int err = 0; + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) return -EFAULT; + #else + if ((u_dump == NULL) || + verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t))) + return -EFAULT; + memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)); + #endif if ((dump.magic != WANPIPE_MAGIC) || (dump.offset + dump.length > card->hw.memory)) return -EINVAL; + #ifdef LINUX_2_0 + if ((dump.ptr == NULL) || + verify_area(VERIFY_WRITE, dump.ptr, dump.length)) + return -EFAULT; + #endif + winsize = card->hw.dpmsize; - save_flags(flags); - cli(); /* >>> critical section start <<< */ if(card->hw.type != SDLA_S514) { + + lock_adapter_irq(&card->wandev.lock, &smp_flags); + oldvec = card->hw.vector; while (dump.length) { /* current offset */ @@ -671,29 +1007,39 @@ err = -EIO; break; } - /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ - sti(); /* Not ideal but tough we have to do this */ + + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)) - return -EFAULT; - cli(); + (u8 *)card->hw.dpmbase + pos, len)){ + + unlock_adapter_irq(&card->wandev.lock, &smp_flags); + return -EFAULT; + } + #else + memcpy_tofs((void*)(dump.ptr), + (void*)(card->hw.dpmbase + pos), len); + #endif dump.length -= len; dump.offset += len; (char*)dump.ptr += len; } + sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ - } - - else { - /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ - sti(); /* Not ideal but tough we have to do this */ + unlock_adapter_irq(&card->wandev.lock, &smp_flags); + + }else { + + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + dump.offset, dump.length)) - return -EFAULT; - cli(); + (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ + return -EFAULT; + } + #else + memcpy_tofs((void*)(dump.ptr), + (void*)(card->hw.dpmbase + dump.offset), dump.length); + #endif } - restore_flags(flags); /* >>> critical section end <<< */ return err; } @@ -703,19 +1049,34 @@ * o copy request structure to kernel data space * o call protocol-specific 'exec' function */ -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec) +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) { sdla_exec_t exec; + int err=0; - if (card->exec == NULL) + if (card->exec == NULL && cmd == WANPIPE_EXEC){ return -ENODEV; - + } + + #if defined(LINUX_2_1) || defined(LINUX_2_4) if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) return -EFAULT; + #else + if ((u_exec == NULL) || + verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t))) + return -EFAULT; + memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)); + #endif if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) return -EINVAL; - return card->exec(card, exec.cmd, exec.data); + + switch (cmd) { + case WANPIPE_EXEC: + err = card->exec(card, exec.cmd, exec.data); + break; + } + return err; } /******* Miscellaneous ******************************************************/ @@ -795,11 +1156,20 @@ return; } + spin_lock(&card->wandev.lock); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } + S514_intack(&card->hw, int_status); - if (card->isr) card->isr(card); + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock(&card->wandev.lock); + /* handle a maximum of two interrupts (one for each */ /* CPU on the adapter) before returning */ if((++ IRQ_count) == 2) @@ -819,17 +1189,19 @@ return; } - /* Use spin lock only for S508 */ - -#ifdef CONFIG_SMP - spin_lock(&card->lock); -#endif + spin_lock(&card->wandev.lock); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } + sdla_intack(&card->hw); if (card->isr) card->isr(card); -#ifdef CONFIG_SMP - spin_unlock(&card->lock); -#endif + + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock(&card->wandev.lock); } @@ -837,33 +1209,6 @@ } /*============================================================================ - * SDLA polling routine. - * This routine simulates kernel thread to perform various housekeeping job. - * - * o for each configured device call its poll() routine - * o if there is at least one active card, then reschedule itself once again - */ -STATIC void sdla_poll (void* data) -{ - int i; - - for (i = 0; i < ncards; ++i) { - sdla_t* card = &card_array[i]; - - if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !card->wandev.critical) { - card->poll(card); - } - } - if (active) { - MOD_INC_USE_COUNT; - if (schedule_task(&sdla_tq) == 0) /* Surely not? */ - MOD_DEC_USE_COUNT; - } - MOD_DEC_USE_COUNT; -} - -/*============================================================================ * This routine is called by the protocol-specific modules when network * interface is being open. The only reason we need this, is because we * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's @@ -892,10 +1237,6 @@ */ void wanpipe_set_state (sdla_t* card, int state) { - unsigned long flags; - - save_flags(flags); - cli(); if (card->wandev.state != state) { switch (state) { case WAN_CONNECTED: @@ -916,7 +1257,187 @@ card->wandev.state = state; } card->state_tick = jiffies; - restore_flags(flags); } -/****** End *****************************************************************/ +sdla_t * wanpipe_find_card (char *name) +{ + int cnt; + for (cnt = 0; cnt < ncards; ++ cnt) { + sdla_t* card = &card_array[cnt]; + if (!strcmp(card->devname,name)) + return card; + } + return NULL; +} +sdla_t * wanpipe_find_card_num (int num) +{ + if (num < 1 || num > ncards) + return NULL; + num--; + return &card_array[num]; +} + + +static void run_wanpipe_tq (unsigned long data) +{ + task_queue *tq_queue = (task_queue *)data; + if (test_and_set_bit(2,(void*)&wanpipe_bh_critical)) + printk(KERN_INFO "CRITICAL IN RUNNING TASK QUEUE\n"); + run_task_queue (tq_queue); + clear_bit(2,(void*)&wanpipe_bh_critical); + +} + +void wanpipe_queue_tq (struct tq_struct *bh_pointer) +{ + if (test_and_set_bit(1,(void*)&wanpipe_bh_critical)) + printk(KERN_INFO "CRITICAL IN QUEUING TASK\n"); + + queue_task(bh_pointer,&wanpipe_tq_custom); + clear_bit(1,(void*)&wanpipe_bh_critical); +} + +void wanpipe_mark_bh (void) +{ + if (!test_and_set_bit(0,(void*)&wanpipe_bh_critical)){ + queue_task(&wanpipe_tq_task,&tq_immediate); + mark_bh(IMMEDIATE_BH); + clear_bit(0,(void*)&wanpipe_bh_critical); + } +} + +void wakeup_sk_bh (netdevice_t *dev) +{ + wanpipe_common_t *chan = dev->priv; + + if (test_bit(0,&chan->common_critical)) + return; + + if (chan->sk && chan->tx_timer){ + chan->tx_timer->expires=jiffies+1; + add_timer(chan->tx_timer); + } +} + +int change_dev_flags (netdevice_t *dev, unsigned flags) +{ + struct ifreq if_info; + mm_segment_t fs = get_fs(); + int err; + + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + if_info.ifr_flags = flags; + + set_fs(get_ds()); /* get user space block */ + err = devinet_ioctl(SIOCSIFFLAGS, &if_info); + set_fs(fs); + + return err; +} + +unsigned long get_ip_address (netdevice_t *dev, int option) +{ + + #ifdef LINUX_2_4 + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = __in_dev_get(dev)) == NULL){ + return 0; + } + #elif defined(LINUX_2_1) + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = dev->ip_ptr) == NULL){ + return 0; + } + #endif + + #if defined(LINUX_2_1) || defined(LINUX_2_4) + if ((ifaddr = in_dev->ifa_list)== NULL ){ + return 0; + } + #endif + + switch (option){ + + case WAN_LOCAL_IP: + #ifdef LINUX_2_0 + return dev->pa_addr; + #else + return ifaddr->ifa_local; + #endif + break; + + case WAN_POINTOPOINT_IP: + #ifdef LINUX_2_0 + return dev->pa_dstaddr; + #else + return ifaddr->ifa_address; + #endif + break; + + case WAN_NETMASK_IP: + #ifdef LINUX_2_0 + return dev->pa_mask; + #else + return ifaddr->ifa_mask; + #endif + break; + + case WAN_BROADCAST_IP: + #ifdef LINUX_2_0 + return dev->pa_brdaddr; + #else + return ifaddr->ifa_broadcast; + #endif + break; + default: + return 0; + } + + return 0; +} + +void add_gateway(sdla_t *card, netdevice_t *dev) +{ + mm_segment_t oldfs; + struct rtentry route; + int res; + + memset((char*)&route,0,sizeof(struct rtentry)); + + ((struct sockaddr_in *) + &(route.rt_dst))->sin_addr.s_addr = 0; + ((struct sockaddr_in *) + &(route.rt_dst))->sin_family = AF_INET; + + ((struct sockaddr_in *) + &(route.rt_genmask))->sin_addr.s_addr = 0; + ((struct sockaddr_in *) + &(route.rt_genmask)) ->sin_family = AF_INET; + + + route.rt_flags = 0; + route.rt_dev = dev->name; + + oldfs = get_fs(); + set_fs(get_ds()); + #if defined(LINUX_2_1) || defined(LINUX_2_4) + res = ip_rt_ioctl(SIOCADDRT,&route); + #else + res = ip_rt_new(&route); + #endif + set_fs(oldfs); + + if (res == 0){ + printk(KERN_INFO "%s: Gateway added for %s\n", + card->devname,dev->name); + } + + return; +} + +/****** End *********************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/wanpipe_multppp.c linux/drivers/net/wan/wanpipe_multppp.c --- v2.4.3/linux/drivers/net/wan/wanpipe_multppp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/wanpipe_multppp.c Thu Apr 12 12:11:39 2001 @@ -0,0 +1,2473 @@ +/***************************************************************************** +* wanpipe_multppp.c Multi-Port PPP driver module. +* +* Authors: Nenad Corbic <ncorbic@sangoma.com> +* +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Dec 15 2000 Updated for 2.4.X kernel +* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. +* The pppstruct has changed. +* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC +* module. +*****************************************************************************/ + +#include <linux/version.h> +#include <linux/kernel.h> /* printk(), and other useful stuff */ +#include <linux/stddef.h> /* offsetof(), etc. */ +#include <linux/errno.h> /* return codes */ +#include <linux/string.h> /* inline memset(), etc. */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ +#include <linux/wanrouter.h> /* WAN router definitions */ +#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ +#include <linux/if_arp.h> /* ARPHRD_* defines */ + +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> +#include <linux/if.h> +#include <asm/byteorder.h> /* htons(), etc. */ +#include <linux/sdlapci.h> +#include <asm/io.h> + +#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ +#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ + +#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ +#include <linux/if_wanpipe.h> + + +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <linux/inetdevice.h> + #include <asm/uaccess.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + #include <net/syncppp.h> +#else + #include "syncppp.h" +#endif + +#else + #include <net/route.h> /* Adding new route entries */ +#endif + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x04 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +#define CRC_LENGTH 2 +#define PPP_HEADER_LEN 4 + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + void *if_ptr; /* General Pointer used by SPPP */ + wanpipe_common_t common; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + + //FIXME: add driver stats as per frame relay! + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats* if_stats (netdevice_t* dev); +#else +static struct enet_statistics* if_stats (netdevice_t* dev); +#endif + +#ifdef LINUX_2_4 +static void if_tx_timeout (netdevice_t *dev); +#endif + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data); +static int chdlc_comm_enable (sdla_t* card); +static int chdlc_comm_disable (sdla_t* card); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int chdlc_send (sdla_t* card, void* data, unsigned len); +static int chdlc_read_comm_err_stats (sdla_t* card); +static int chdlc_read_op_stats (sdla_t* card); +static int config_chdlc (sdla_t *card); + + +/* Miscellaneous CHDLC Functions */ +static int set_chdlc_config (sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev ); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); +static int process_chdlc_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area); +static void port_set_state (sdla_t *card, int); + +/* Interrupt handlers */ +static void wsppp_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Miscellaneous functions */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area); +static unsigned short calc_checksum (char *, int); +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); +static void send_ppp_term_request (netdevice_t*); + + +static int Intr_test_counter; +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wsppp_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + unsigned long max_permitted_baud = 0; + SHARED_MEMORY_INFO_STRUCT *flags; + + union + { + char str[80]; + } u; + volatile CHDLC_MAILBOX_STRUCT* mb; + CHDLC_MAILBOX_STRUCT* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_MPPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_ERR "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + if(card->hw.type != SDLA_S514){ + + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox = (void *) card->hw.dpmbase; + }else{ + card->mbox = (void *) card->hw.dpmbase + + SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; + } + }else{ + /* for a S514 adapter, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; + } + } + + mb = mb1 = card->mbox; + + if (!card->configured){ + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" + "%s: for Multi-Port PPP protocol.\n", + card->devname,u.str,card->devname); + + card->isr = &wsppp_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->hw.type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + + card->wandev.clocking = conf->clocking; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + if(card->wandev.clocking) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->hw.type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + } + else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->hw.type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* Setup the Port MTU */ + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } + + /* Add on a PPP Header */ + card->wandev.mtu += PPP_HEADER_LEN; + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->buffer_length = 0; + mb1->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; + if(err != COMMAND_OK) { + clear_bit(1, (void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + enable_irq(card->hw.irq); + + chdlc_error(card, err, mb1); + return -EIO; + } + + if(card->hw.type == SDLA_S514){ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct)); + }else{ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + } + + flags = card->u.c.flags; + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + + if (!card->wandev.piggyback){ + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk(KERN_ERR "%s: Interrupt test failed (%i)\n", + card->devname, Intr_test_counter); + printk(KERN_ERR "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, Intr_test_counter); + } + + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile chdlc_private_area_t* chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags; + unsigned long timeout; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(!card->u.c.flags) + return -ENODEV; + + if((dev=card->wandev.dev) == NULL) + return -ENODEV; + + if((chdlc_priv_area=dev->priv) == NULL) + return -ENODEV; + + flags = card->u.c.flags; + + if(chdlc_priv_area->update_comms_stats){ + return -EAGAIN; + } + + /* we will need 2 timer interrupts to complete the */ + /* reading of the statistics */ + chdlc_priv_area->update_comms_stats = 2; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(chdlc_priv_area->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + chdlc_priv_area->update_comms_stats = 0; + chdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } + + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* pdev, wanif_conf_t* conf) +{ + + struct ppp_device *pppdev = (struct ppp_device *)pdev; + netdevice_t *dev=NULL; + struct sppp *sp; + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if(chdlc_priv_area == NULL) + return -ENOMEM; + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + + /* initialize data */ + strcpy(card->u.c.if_name, conf->name); + + if(card->wandev.new_if_cnt > 0) { + kfree(chdlc_priv_area); + return -EEXIST; + } + + card->wandev.new_if_cnt++; + + chdlc_priv_area->TracingEnabled = 0; + + //We don't need this any more + chdlc_priv_area->route_status = NO_ROUTE; + chdlc_priv_area->route_removed = 0; + + printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", + wandev->name); + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", + wandev->name); + card->u.c.usedby = WANPIPE; + } else { + printk(KERN_INFO + "%s: API Mode is not supported for SyncPPP!\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; + } + + /* Get Multicast Information */ + chdlc_priv_area->mc = conf->mc; + + + chdlc_priv_area->if_ptr = pppdev; + + /* prepare network device data space for registration */ + + /* Attach PPP protocol layer to pppdev + * The sppp_attach() will initilize the dev structure + * and setup ppp layer protocols. + * All we have to do is to bind in: + * if_open(), if_close(), if_send() and get_stats() functions. + */ + sppp_attach(pppdev); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) + dev = pppdev->dev; + #else + dev = &pppdev->dev; + #endif + sp = &pppdev->sppp; + + /* Enable PPP Debugging */ + // FIXME Fix this up somehow + //sp->pp_flags |= PP_DEBUG; + sp->pp_flags &= ~PP_CISCO; + + #ifdef LINUX_2_4 + strcpy(dev->name,card->u.c.if_name); + #else + dev->name = (char *)kmalloc(strlen(card->u.c.if_name) + 2, GFP_KERNEL); + sprintf(dev->name, "%s", card->u.c.if_name); + #endif + + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + return 0; +} + + + + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + unsigned long smp_lock; + + /* Detach the PPP layer */ + printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", + wandev->name,dev->name); + + lock_adapter_irq(&wandev->lock,&smp_lock); + + sppp_detach(dev); + chdlc_priv_area->if_ptr=NULL; + + chdlc_set_intr_mode(card, 0); + if (card->u.c.comm_enabled) + chdlc_comm_disable(card); + unlock_adapter_irq(&wandev->lock,&smp_lock); + + port_set_state(card, WAN_DISCONNECTED); + + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) + { + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + #ifdef LINUX_2_0 + int i; + #endif + + /* NOTE: Most of the dev initialization was + * done in sppp_attach(), called by new_if() + * function. All we have to do here is + * to link four major routines below. + */ + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + #ifdef LINUX_2_4 + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + #endif + + + #ifdef LINUX_2_0 + dev->family = AF_INET; + #endif + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If we over fill this queue the packets will + * be droped by the kernel. + * sppp_attach() sets this to 10, but + * 100 will give us more room at low speeds. + */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + #if defined(LINUX_2_1) || defined(LINUX_2_4) + dev_init_buffers(dev); + #else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); + #endif + + return 0; +} + + +#ifdef LINUX_2_4 +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} +#endif + + + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + struct timeval tv; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + /* Only one open per interface is allowed */ + + #ifdef LINUX_2_4 + if (netif_running(dev)) + return -EBUSY; + #else + if (dev->start) + return -EBUSY; /* only one open is allowed */ + #endif + + /* Start PPP Layer */ + if (sppp_open(dev)){ + return -EIO; + } + + do_gettimeofday(&tv); + chdlc_priv_area->router_start_time = tv.tv_sec; + + #ifdef LINUX_2_4 + netif_start_queue(dev); + #else + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + #endif + + wanpipe_open(card); + + chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + /* Stop the PPP Layer */ + sppp_close(dev); + stop_net_queue(dev); + + #ifndef LINUX_2_4 + dev->start=0; + #endif + + wanpipe_close(card); + + return 0; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; + int udp_type = 0; + unsigned long smp_flags; + int err=0; + + #ifdef LINUX_2_4 + netif_stop_queue(dev); + #endif + + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + + #ifndef LINUX_2_4 + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit (tbusy) timeout !\n", + card->devname); + + /* unbusy the interface */ + dev->tbusy = 0; + } + #endif + + if (ntohs(skb->protocol) != htons(PVC_PROT)){ + /* check the udp packet type */ + + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_CPIPE_TYPE){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chdlc_priv_area)){ + chdlc_int->interrupt_permission |= + APP_INT_ON_TIMER; + } + start_net_queue(dev); + return 0; + } + } + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (chdlc_send(card, skb->data, skb->len)){ + stop_net_queue(dev); + + }else{ + ++card->wandev.stats.tx_packets; + #if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.tx_bytes += skb->len; + #endif + #ifdef LINUX_2_4 + dev->trans_start = jiffies; + #endif + start_net_queue(dev); + } + +if_send_crit_exit: + if (!(err=is_queue_stopped(dev))){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + chdlc_priv_area->tick_counter = jiffies; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + sizeof(trace_info_t)+ + mbox_len; + + /* fill in UDP reply */ + c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + sizeof(trace_info_t)+ + mbox_len; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + c_udp_pkt->udp_pkt.udp_length = temp; + + /* swap UDP ports */ + temp = c_udp_pkt->udp_pkt.udp_src_port; + c_udp_pkt->udp_pkt.udp_src_port = + c_udp_pkt->udp_pkt.udp_dst_port; + c_udp_pkt->udp_pkt.udp_dst_port = temp; + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; + + + /* calculate UDP checksum */ + c_udp_pkt->udp_pkt.udp_checksum = 0; + c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + c_udp_pkt->ip_pkt.total_length = temp; + + /* swap IP addresses */ + ip_temp = c_udp_pkt->ip_pkt.ip_src_address; + c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; + c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + + /* fill in IP checksum */ + c_udp_pkt->ip_pkt.hdr_checksum = 0; + c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} +#else +static struct enet_statistics* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} +#endif + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data) +{ + int err; + CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mailbox->buffer_length = data_length; + memcpy(mailbox->data, data, data_length); + mailbox->command = SET_CHDLC_CONFIGURATION; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mailbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 1; + + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled=1; + + return err; +} + +/*============================================================================ + * Disable communications and Drop the Modem lines (DCD and RTS). + */ +static int chdlc_comm_disable (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int chdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = READ_COMMS_ERROR_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int chdlc_read_op_stats (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_OPERATIONAL_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* on the first timer interrupt, read the comms error statistics */ + if(chdlc_priv_area->update_comms_stats == 2) { + if(chdlc_read_comm_err_stats(card)) + return 1; + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->sec_Tx_abort_count; + } + + /* on the second timer interrupt, read the operational statistics */ + else { + if(chdlc_read_op_stats(card)) + return 1; + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; + card->wandev.stats.rx_length_errors = + (op_stats->Rx_Data_discard_short_count + + op_stats->Rx_Data_discard_long_count); + } + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; + + if (txbuf->opp_flag) + return 1; + + sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); + + txbuf->frame_length = len; + txbuf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.c.txbuf = ++txbuf; + + if ((void*)txbuf > card->u.c.txbuf_last) + card->u.c.txbuf = card->u.c.txbuf_base; + + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wsppp_isr (sdla_t* card) +{ + netdevice_t* dev; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + int i; + sdla_t *my_card; + + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + flags = card->u.c.flags; + if (!flags->interrupt_info_struct.interrupt_type){ + /* Check for a second port (piggybacking) */ + if((my_card = card->next)){ + flags = my_card->u.c.flags; + if (flags->interrupt_info_struct.interrupt_type){ + card = my_card; + card->isr(card); + return; + } + } + } + + dev = card->wandev.dev; + card->in_isr = 1; + flags = card->u.c.flags; + + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + goto isr_done; + } + + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + flags->interrupt_info_struct. + interrupt_type = 0; + goto isr_done; + } + + + /* On a 508 Card, if critical due to if_send + * Major Error !!! + */ + if(card->hw.type != SDLA_S514) { + if(test_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: %lx\n", + card->devname, card->wandev.critical); + goto isr_done; + } + } + + switch(flags->interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TX_FRAME; + + wake_net_dev(dev); + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ Intr_test_counter; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_chdlc_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags->interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codename[i]); + printk(KERN_INFO "\nCode version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + break; + } + +isr_done: + card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + netdevice_t *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; + struct sk_buff *skb; + unsigned len; + unsigned addr = rxbuf->ptr_data_bfr; + void *buf; + int i,udp_type; + + if (rxbuf->opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codename[i]); + printk(KERN_INFO "\nCode version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); + return; + } + + dev = card->wandev.dev; + + if (!dev){ + goto rx_exit; + } + + #ifdef LINUX_2_4 + if (!netif_running(dev)){ + goto rx_exit; + } + #else + if (!dev->start){ + goto rx_exit; + } + #endif + + chdlc_priv_area = dev->priv; + + if (rxbuf->error_flag){ + goto rx_exit; + } + /* Take off two CRC bytes */ + + if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ + goto rx_exit; + } + + len = rxbuf->frame_length - CRC_LENGTH; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb == NULL) { + if (net_ratelimit()){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top + 1) { + unsigned tmp = card->u.c.rx_top - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + skb->protocol = htons(ETH_P_WAN_PPP); + + card->wandev.stats.rx_packets ++; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.rx_bytes += skb->len; +#endif + udp_type = udp_pkt_type( skb, card ); + + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + flags->interrupt_info_struct. + interrupt_permission |= + APP_INT_ON_TIMER; + } + }else{ + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb = ++ rxbuf; + if((void*)rxbuf > card->u.c.rxbuf_last){ + card->u.c.rxmb = card->u.c.rxbuf_base; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t* dev; + chdlc_private_area_t* chdlc_priv_area = NULL; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + + dev = card->wandev.dev; + chdlc_priv_area = dev->priv; + + if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + if (!config_chdlc(card)){ + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + } + + /* process a udp call if pending */ + if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + chdlc_priv_area); + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + + /* read the communications statistics if required */ + if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, chdlc_priv_area); + if(!(-- chdlc_priv_area->update_comms_stats)) { + chdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!chdlc_priv_area->timer_int_enabled) { + flags = card->u.c.flags; + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_chdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_chdlc_config(sdla_t* card) +{ + + CHDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + //API OPTIONS + cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; + cfg.modem_status_timer = 100; + cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + cfg.max_CHDLC_data_field_length = card->wandev.mtu; + + cfg.transmit_keepalive_timer = 0; + cfg.receive_keepalive_timer = 0; + cfg.keepalive_error_tolerance = 0; + cfg.SLARP_request_timer = 0; + + cfg.IP_address = 0; + cfg.IP_netmask = 0; + + return chdlc_configure(card, &cfg); +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + int err; + + mbox->buffer_length = 0; + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if(err != CMD_TIMEOUT ){ + + switch(mbox->return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + + if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ + //printk(KERN_INFO "Sending TERM Request Manually !\n"); + send_ppp_term_request(card->wandev.dev); + } + break; + + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "%s: Line trace disabled\n", + card->devname); + break; + + case EXCEP_IRQ_TIMEOUT: + printk(KERN_INFO "%s: IRQ timeout occurred\n", + card->devname); + break; + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mbox->return_code); + break; + } + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_EXCEPTION_CONDITION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_LINK_ACTIVE: + port_set_state(card, WAN_CONNECTED); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + port_set_state(card, WAN_DISCONNECTED); + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "%s: Loopback Condition Detected.\n", + card->devname); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "%s: No exceptions reported.\n", + card->devname); + break; + default: + printk(KERN_INFO "%s: Exception Condition %x!\n", + card->devname,err); + break; + } + + } + return 0; +} + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!chdlc_priv_area->udp_pkt_lgth && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + chdlc_priv_area->udp_pkt_lgth = skb->len; + chdlc_priv_area->udp_pkt_src = udp_pkt_src; + memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); + chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK) + wan_dev_kfree_skb(skb, FREE_WRITE); + else + wan_dev_kfree_skb(skb, FREE_READ); + + return(udp_pkt_stored); +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + unsigned char *buf; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + CHDLC_MAILBOX_STRUCT *mb = card->mbox; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + chdlc_udp_pkt_t *chdlc_udp_pkt; + struct timeval tv; + int err; + char ut_char; + + chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(chdlc_udp_pkt->cblock.command) { + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_CHDLC_LINK_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_CHDLC_OPERATIONAL_STATS: + + /* These two commands are executed for + * each request */ + case READ_CHDLC_CONFIGURATION: + case READ_CHDLC_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + chdlc_udp_pkt->cblock.buffer_length = 0; + + /* set return code */ + chdlc_udp_pkt->cblock.return_code = 0xCD; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,chdlc_udp_pkt->cblock.command); + } + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + switch(chdlc_udp_pkt->cblock.command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Configure the Trace based on user inputs */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= + chdlc_udp_pkt->data[0]; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_deactivation_timer = 4000; + + + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->buffer_length = 0; + mb->command = READ_TRACE_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->data) -> ptr_trace_stat_el_cfg_struct; + + sdla_peek(&card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = + trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = + trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = + trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = + trace_cfg_struct.next_trace_element_to_use; + + chdlc_priv_area->available_buffer_space = 2000 - + sizeof(ip_pkt_t) - + sizeof(udp_pkt_t) - + sizeof(wp_mgmt_t) - + sizeof(cblock_t) - + sizeof(trace_info_t); + } + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_INACTIVE; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + + chdlc_priv_area->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + chdlc_udp_pkt->cblock.return_code = 1; + mb->buffer_length = 0; + break; + } + + chdlc_udp_pkt->trace_info.ismoredata = 0x00; + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ + + trace_pkt_t *trace_pkt = (trace_pkt_t *) + &chdlc_udp_pkt->data[buffer_length]; + + sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + if (data_ptr){ + data_length = trace_element_struct.trace_length; + }else{ + data_length = 0; + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + } + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(trace_pkt_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + break; + } + + trace_pkt->status = trace_element_struct.trace_type; + + trace_pkt->time_stamp = + trace_element_struct.trace_time_stamp; + + trace_pkt->real_length = + trace_element_struct.trace_length; + + /* see if we can fit the frame into the user buffer */ + real_len = trace_pkt->real_length; + + if (data_ptr == 0) { + trace_pkt->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + trace_pkt->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1){ + + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + sdla_peek(&card->hw, data_ptr, + trace_pkt->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + sdla_peek(&card->hw, data_ptr, + &trace_pkt->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + ut_char = 0x00; + sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + if(trace_pkt->data_avail == 0x01) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(trace_pkt_t); + + } /* For Loop */ + + if (frames == chdlc_priv_area->number_trace_elements){ + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + } + chdlc_udp_pkt->trace_info.num_frames = frames; + + mb->buffer_length = buffer_length; + chdlc_udp_pkt->cblock.buffer_length = buffer_length; + + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + ((unsigned char *)chdlc_udp_pkt->data )[0] = + flags->FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)chdlc_udp_pkt->data )[1] = + flags->FT1_info_struct.parallel_port_B_input; + + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&chdlc_udp_pkt->data = + chdlc_priv_area->router_up_time; + mb->buffer_length = sizeof(unsigned long); + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || + (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + chdlc_udp_pkt->cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( chdlc_udp_pkt->data[0] == 0) { + + if( --rCount != 0) { + chdlc_udp_pkt->cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + default: + /* it's a board command */ + mb->command = chdlc_udp_pkt->cblock.command; + mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; + if (mb->buffer_length) { + memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> + data, mb->buffer_length); + } + /* run the command on the board */ + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + break; + } + + /* copy the result back to our buffer */ + memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); + + if (mb->buffer_length) { + memcpy(&chdlc_udp_pkt->data, &mb->data, + mb->buffer_length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + + len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; +#if defined(LINUX_2_1) || defined(LINUX_2_4) + card->wandev.stats.tx_bytes += len; +#endif + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, chdlc_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + chdlc_priv_area->udp_pkt_lgth = 0; + + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev ) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; + char err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + if(card->hw.type == SDLA_S514) { + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct)); + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base = (void *)(card->hw.dpmbase + + tx_config->base_addr_Tx_status_elements); + card->u.c.txbuf_last = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base + + (tx_config->number_Tx_status_elements - 1); + + card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + + rx_config->base_addr_Rx_status_elements); + card->u.c.rxbuf_last = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base + + (rx_config->number_Rx_status_elements - 1); + + /* Set up next pointer to be used */ + card->u.c.txbuf = (void *)(card->hw.dpmbase + + tx_config->next_Tx_status_element_to_use); + card->u.c.rxmb = (void *)(card->hw.dpmbase + + rx_config->next_Rx_status_element_to_use); + } + else { + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base = (void *)(card->hw.dpmbase + + (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.txbuf_last = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base + + (tx_config->number_Tx_status_elements - 1); + card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + + (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.rxbuf_last = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base + + (rx_config->number_Rx_status_elements - 1); + + /* Set up next pointer to be used */ + card->u.c.txbuf = (void *)(card->hw.dpmbase + + (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); + card->u.c.rxmb = (void *)(card->hw.dpmbase + + (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); + } + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base = rx_config->base_addr_Rx_buffer; + card->u.c.rx_top = rx_config->end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err,i; + + Intr_test_counter = 0; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpc_isr is + * called it does not exit due to critical flag set. + */ + + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + } + else { + return err; + } + + err = chdlc_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; + + if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && + (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && + (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + return UDP_CPIPE_TYPE; + } + else return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + + if (card->u.c.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: HDLC link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: HDLC link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: HDLC link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = card->u.c.state = state; + chdlc_priv_area->common.state = state; + } +} + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + #if defined(__SMP__) || defined(LINUX_2_4) + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + /* It is ok to use spin_lock here, since we + * already turned off interrupts */ + spin_lock(&card->next->wandev.lock); + } + #else + disable_irq(card->hw.irq); + #endif +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + #if defined(__SMP__) || defined(LINUX_2_4) + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); + #else + enable_irq(card->hw.irq); + #endif +} + + + +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card) +{ + netdevice_t *dev = card->wandev.dev; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + + if (card->u.c.comm_enabled){ + chdlc_comm_disable(card); + port_set_state(card, WAN_DISCONNECTED); + } + + if (set_chdlc_config(card)) { + printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", + card->devname); + return 0; + } + init_chdlc_tx_rx_buff(card, dev); + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return 0; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + flags->interrupt_info_struct.interrupt_permission = 0; + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return 0; + } + + /* Initialize Rx/Tx buffer control fields */ + port_set_state(card, WAN_CONNECTING); + return 0; +} + + +static void send_ppp_term_request (netdevice_t *dev) +{ + struct sk_buff *new_skb; + unsigned char *buf; + + if ((new_skb = dev_alloc_skb(8)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, 8); + sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_WAN_PPP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } +} + + +/****** End ****************************************************************/ diff -u --recursive --new-file v2.4.3/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.3/linux/drivers/parport/ChangeLog Sun Mar 25 18:22:01 2001 +++ linux/drivers/parport/ChangeLog Thu Apr 12 12:05:50 2001 @@ -1,3 +1,20 @@ +2001-04-08 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (parport_pc_save_state): Read from the soft copy of + the control port. + (parport_pc_restore_state): Update the soft copy of the control + port. + +2001-03-26 Tim Waugh <twaugh@redhat.com> + + * share.c (parport_find_number, parport_find_base): Trigger + a lowlevel driver load if there are no ports yet. + +2001-03-26 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (parport_ECP_supported): Remove the IRQ conflict + check since it seems totally unreliable. + 2001-03-02 Tim Waugh <twaugh@redhat.com> * ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd diff -u --recursive --new-file v2.4.3/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.4.3/linux/drivers/parport/parport_pc.c Mon Mar 26 15:41:19 2001 +++ linux/drivers/parport/parport_pc.c Thu Apr 12 12:05:50 2001 @@ -347,15 +347,16 @@ void parport_pc_save_state(struct parport *p, struct parport_state *s) { const struct parport_pc_private *priv = p->physport->private_data; - s->u.pc.ctr = inb (CONTROL (p)); + s->u.pc.ctr = priv->ctr; if (priv->ecr) s->u.pc.ecr = inb (ECONTROL (p)); } void parport_pc_restore_state(struct parport *p, struct parport_state *s) { - const struct parport_pc_private *priv = p->physport->private_data; + struct parport_pc_private *priv = p->physport->private_data; outb (s->u.pc.ctr, CONTROL (p)); + priv->ctr = s->u.pc.ctr; if (priv->ecr) outb (s->u.pc.ecr, ECONTROL (p)); } diff -u --recursive --new-file v2.4.3/linux/drivers/pci/Makefile linux/drivers/pci/Makefile --- v2.4.3/linux/drivers/pci/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/pci/Makefile Fri Apr 13 20:31:32 2001 @@ -21,6 +21,7 @@ # obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o +obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o diff -u --recursive --new-file v2.4.3/linux/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c --- v2.4.3/linux/drivers/pci/setup-res.c Mon Dec 11 13:46:26 2000 +++ linux/drivers/pci/setup-res.c Fri Apr 6 10:51:19 2001 @@ -163,6 +163,10 @@ size = ln->res->end - ln->res->start; if (r_size > size) { tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + printk("pdev_sort_resources(): kmalloc() failed!\n"); + continue; + } tmp->next = ln; tmp->res = r; tmp->dev = dev; diff -u --recursive --new-file v2.4.3/linux/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c --- v2.4.3/linux/drivers/pcmcia/hd64465_ss.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/pcmcia/hd64465_ss.c Thu Apr 12 12:16:35 2001 @@ -30,7 +30,6 @@ #include <linux/types.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/config.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/ioport.h> diff -u --recursive --new-file v2.4.3/linux/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c --- v2.4.3/linux/drivers/pcmcia/pci_socket.c Thu Nov 16 16:38:16 2000 +++ linux/drivers/pcmcia/pci_socket.c Fri Apr 6 10:51:19 2001 @@ -172,13 +172,20 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops) { pci_socket_t *socket = nr + pci_socket_array; - + int err; + memset(socket, 0, sizeof(*socket)); socket->dev = dev; socket->op = ops; dev->driver_data = socket; spin_lock_init(&socket->event_lock); - return socket->op->open(socket); + err = socket->op->open(socket); + if(err) + { + socket->dev = NULL; + dev->driver_data = NULL; + } + return err; } void cardbus_register(pci_socket_t *socket) @@ -195,8 +202,7 @@ for (s = 0; s < MAX_SOCKETS; s++) { if (pci_socket_array [s].dev == 0) { - add_pci_socket (s, dev, ¥ta_operations); - return 0; + return add_pci_socket (s, dev, ¥ta_operations); } } return -ENODEV; diff -u --recursive --new-file v2.4.3/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.4.3/linux/drivers/pcmcia/yenta.c Thu Nov 16 18:25:16 2000 +++ linux/drivers/pcmcia/yenta.c Fri Apr 6 10:51:19 2001 @@ -755,6 +755,9 @@ */ static void yenta_close(pci_socket_t *sock) { + /* Disable all events so we don't die in an IRQ storm */ + cb_writel(sock, CB_SOCKET_MASK, 0x0); + if (sock->cb_irq) free_irq(sock->cb_irq, sock); else diff -u --recursive --new-file v2.4.3/linux/drivers/s390/Config.in linux/drivers/s390/Config.in --- v2.4.3/linux/drivers/s390/Config.in Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/Config.in Wed Apr 11 19:02:29 2001 @@ -7,7 +7,7 @@ if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 24576 fi -dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM tristate 'XPRAM disk support' CONFIG_BLK_DEV_XPRAM comment 'S/390 block device drivers' @@ -18,7 +18,7 @@ bool ' Support for FBA Disks' CONFIG_DASD_FBA # bool ' Support for CKD Disks' CONFIG_DASD_CKD if [ "$CONFIG_ARCH_S390" = "y" ]; then - bool ' Support for DIAG access to CMS reserved Disks' CONFIG_DASD_MDSK + bool ' Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG fi; fi @@ -35,9 +35,15 @@ comment 'S/390 character device drivers' -bool 'Support for 3215 line mode terminal' CONFIG_3215 -if [ "$CONFIG_3215" = "y" ]; then - bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE +tristate 'Support for locally attached 3270 tubes' CONFIG_3270 +if [ "$CONFIG_3270" = "y" ]; then + bool 'Support for console on 3270 line mode terminal' CONFIG_3270_CONSOLE +fi +if [ "$CONFIG_3270_CONSOLE" != "y" ]; then + bool 'Support for 3215 line mode terminal' CONFIG_3215 + if [ "$CONFIG_3215" = "y" ]; then + bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE + fi fi bool 'Support for HWC line mode terminal' CONFIG_HWC if [ "$CONFIG_HWC" = "y" ]; then diff -u --recursive --new-file v2.4.3/linux/drivers/s390/Makefile linux/drivers/s390/Makefile --- v2.4.3/linux/drivers/s390/Makefile Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/Makefile Wed Apr 11 19:02:29 2001 @@ -1,39 +1,14 @@ # -# Makefile for the linux i386-specific parts of the memory manager. +# Makefile for the S/390 specific device drivers # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... - -all: io.o -CFLAGS += O_TARGET := io.o -obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o - subdir-y := block char misc net subdir-m := $(subdir-y) +obj-y := $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o) -obj-y += block/s390-block.o \ - char/s390-char.o \ - misc/s390-misc.o \ - net/s390-net.o - -io.o: $(obj-y) - -block/s390-block.o: dummy - $(MAKE) -C block - -char/s390-char.o: dummy - $(MAKE) -C char - -misc/s390-misc.o: dummy - $(MAKE) -C misc - -net/s390-net.o: dummy - $(MAKE) -C net +obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o +export-objs += ccwcache.o idals.o s390dyn.o s390io.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile --- v2.4.3/linux/drivers/s390/block/Makefile Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/Makefile Wed Apr 11 19:02:28 2001 @@ -1,34 +1,22 @@ -all: s390-block.o +# +# S/390 block devices +# -CFLAGS += O_TARGET := s390-block.o -DASD_OBJS := dasd.o - ifeq ($(CONFIG_DASD_ECKD),y) - DASD_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o - endif - ifeq ($(CONFIG_DASD_FBA),y) - DASD_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o - endif - ifeq ($(CONFIG_DASD_MDSK),y) - DASD_OBJS += dasd_mdsk.o - endif -# ifeq ($(CONFIG_DASD_CKD),y) -# DASD_OBJS += dasd_ckd.o -# endif - -ifeq ($(CONFIG_DASD),y) - obj-y += $(DASD_OBJS) -else - ifeq ($(CONFIG_DASD),m) - obj-m += dasd_mod.o - D_OBJS += $(DASD_OBJS) - endif -endif +list-multi := dasd_mod.o +export-objs := dasd.o -obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o +dasd_mod-$(CONFIG_DASD_ECKD) += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o +dasd_mod-$(CONFIG_DASD_FBA) += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o +dasd_mod-$(CONFIG_DASD_DIAG) += dasd_diag.o +dasd_mod-objs := dasd.o $(dasd_mod-y) -dasd_mod.o: $(D_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS) +obj-$(CONFIG_DASD) += dasd_mod.o +obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o include $(TOPDIR)/Rules.make + +dasd_mod.o: $(dasd_mod-objs) + $(LD) -r -o $@ $(dasd_mod-objs) + diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c --- v2.4.3/linux/drivers/s390/block/dasd.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/s390/block/dasd.c Wed Apr 11 19:02:28 2001 @@ -2,13 +2,27 @@ * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com> + * Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * History of changes (starts July 2000) * 11/09/00 complete redesign after code review + * 02/01/01 removed some warnings + * 02/01/01 added dynamic registration of ioctls + * fixed bug in registration of new majors + * fixed handling of request during dasd_end_request + * fixed handling of plugged queues + * fixed partition handling and HDIO_GETGEO + * fixed traditional naming scheme for devices beyond 702 + * fixed some race conditions related to modules + * added devfs suupport + * 03/06/01 refined dynamic attach/detach for leaving devices which are online. + * 06/09/01 refined dynamic modifiaction of devices + * renewed debug feature exploitation */ +#include <linux/module.h> #include <linux/config.h> #include <linux/version.h> #include <linux/init.h> @@ -17,7 +31,7 @@ #include <linux/kernel.h> #include <linux/tqueue.h> #include <linux/timer.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/interrupt.h> @@ -25,13 +39,9 @@ #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> #endif /* CONFIG_PROC_FS */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) #include <linux/spinlock.h> #include <linux/devfs_fs_kernel.h> #include <linux/blkpg.h> -#else -#include <asm/spinlock.h> -#endif #include <asm/ccwcache.h> #include <asm/dasd.h> @@ -54,17 +64,10 @@ #ifdef CONFIG_DASD_FBA #include "dasd_fba.h" #endif /* CONFIG_DASD_FBA */ -#ifdef CONFIG_DASD_MDSK +#ifdef CONFIG_DASD_DIAG #include "dasd_diag.h" -#endif /* CONFIG_DASD_MDSK */ - -static struct block_device_operations dasd_device_operations; +#endif /* CONFIG_DASD_DIAG */ -#ifdef MODULE -#define EXPORT_SYMTAB -#include <linux/module.h> - -EXPORT_NO_SYMBOLS; MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>"); MODULE_DESCRIPTION ("Linux on S/390 DASD device driver," " Copyright 2000 IBM Corporation"); @@ -76,11 +79,10 @@ EXPORT_SYMBOL (dasd_int_handler); EXPORT_SYMBOL (dasd_alloc_request); EXPORT_SYMBOL (dasd_free_request); - -#endif /* MODULE */ +EXPORT_SYMBOL(dasd_ioctl_no_register); +EXPORT_SYMBOL(dasd_ioctl_no_unregister); /* SECTION: Constant definitions to be used within this file */ -#undef ERP_DEBUG #define PRINTK_HEADER DASD_NAME": " @@ -89,20 +91,28 @@ #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE #define DASD_CHANQ_MAX_SIZE 6 - /* SECTION: prototypes for static functions of dasd.c */ static request_fn_proc do_dasd_request; -void dasd_schedule_bh (dasd_device_t *); static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int); static request_queue_t *dasd_get_queue (kdev_t kdev); +static void cleanup_dasd (void); +int dasd_fillgeo(int kdev,struct hd_geometry *geo); static struct block_device_operations dasd_device_operations; +/* SECTION: static variables of dasd.c */ + +static devfs_handle_t dasd_devfs_handle; + +/* SECTION: exported variables of dasd.c */ + +debug_info_t *dasd_debug_area; + #ifdef CONFIG_DASD_DYNAMIC /* SECTION: managing dynamic configuration of dasd_driver */ -static dasd_devreg_t *dasd_devreg_head = NULL; +static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head); /* * function: dasd_create_devreg @@ -149,6 +159,7 @@ static dasd_range_t *dasd_range_head = NULL; /* anchor for list of ranges */ static spinlock_t range_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t dasd_open_count_lock; /* * function: dasd_create_range @@ -240,15 +251,14 @@ * appends it to the list of ranges * additionally a devreg_t is created and added to the list of devregs */ -static inline void +static inline dasd_range_t* dasd_add_range (int from, int to) { dasd_range_t *range; range = dasd_create_range (from, to); - if (range) - dasd_append_range (range); - else - return; + if (!range) return NULL; + + dasd_append_range (range); #ifdef CONFIG_DASD_DYNAMIC /* allocate and chain devreg infos for the devnos... */ { @@ -256,11 +266,11 @@ for (i = range->from; i <= range->to; i++) { dasd_devreg_t *reg = dasd_create_devreg (i); s390_device_register (®->devreg); - reg->next = dasd_devreg_head; - dasd_devreg_head = reg; + list_add(®->list,&dasd_devreg_head); } } #endif /* CONFIG_DASD_DYNAMIC */ + return range; } /* @@ -277,28 +287,25 @@ { int i; for (i = range->from; i <= range->to; i++) { - dasd_devreg_t *reg, *prev = NULL; - for (reg = dasd_devreg_head; reg; reg = reg->next) { + struct list_head *l; + dasd_devreg_t *reg = NULL; + list_for_each (l, &dasd_devreg_head) { + reg = list_entry(l,dasd_devreg_t,list); if (reg->devreg.flag == DEVREG_TYPE_DEVNO && - reg->devreg.devno == i && + reg->devreg.ci.devno == i && reg->devreg.oper_func == dasd_oper_handler) break; - prev = reg; } - if (!reg) + if (l == &dasd_devreg_head) BUG (); - if (prev) { - prev->next = reg->next; - } else { - dasd_devreg_head = reg->next; - } + list_del(®->list); s390_device_unregister (®->devreg); dasd_destroy_devreg (reg); } } +#endif /* CONFIG_DASD_DYNAMIC */ dasd_dechain_range (range); dasd_destroy_range (range); -#endif /* CONFIG_DASD_DYNAMIC */ } /* @@ -475,13 +482,18 @@ /* SECTION: Dealing with devices registered to multiple major numbers */ static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED; + static major_info_t dasd_major_info[] = { { - next:NULL, + list: LIST_HEAD_INIT(dasd_major_info[1].list ) + }, + { + list: LIST_HEAD_INIT(dasd_major_info[0].list ), gendisk: { INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) - } + }, + flags : DASD_MAJOR_INFO_IS_STATIC } }; @@ -489,26 +501,16 @@ get_new_major_info (void) { major_info_t *major_info = NULL; - unsigned long flags; major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL); if (major_info) { - major_info_t *temp = dasd_major_info; - static major_info_t temp_major_info[] = - { - { - next:NULL, - gendisk: { - INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) - } - } - }; - spin_lock_irqsave (&dasd_major_lock, flags); - while (temp->next) - temp = temp->next; - temp->next = major_info; - spin_unlock_irqrestore (&dasd_major_lock, flags); - memcpy (major_info, temp_major_info, sizeof (major_info_t)); + static major_info_t temp_major_info = + { + gendisk: { + INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) + } + }; + memcpy (major_info, &temp_major_info, sizeof (major_info_t)); } return major_info; } @@ -518,6 +520,7 @@ { int rc = 0; int major; + unsigned long flags; if (major_info == NULL) { major_info = get_new_major_info (); @@ -531,12 +534,27 @@ } } major = major_info->gendisk.major; + major_info->gendisk.de_arr = (devfs_handle_t*) + kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL); + memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t)); + major_info->gendisk.flags = (char*) + kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL); + memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char)); + rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Cannot register to major no %d, rc = %d\n", major, rc); return rc; + } else { + major_info->flags |= DASD_MAJOR_INFO_REGISTERED; } + /* Insert the new major info into dasd_major_info if needed */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){ + spin_lock_irqsave (&dasd_major_lock, flags); + list_add_tail(&major_info->list,&dasd_major_info[0].list); + spin_unlock_irqrestore (&dasd_major_lock, flags); + } if (major == 0) { major = rc; rc = 0; @@ -604,6 +622,7 @@ int rc = 0; int major; struct gendisk *dd, *prev = NULL; + unsigned long flags; if (major_info == NULL) { return -EINVAL; @@ -629,6 +648,8 @@ if (dd == NULL) { return -ENOENT; } + kfree (major_info->gendisk.de_arr); + kfree (major_info->gendisk.flags); kfree (major_info->dasd_device); kfree (blk_size[major]); kfree (blksize_size[major]); @@ -641,9 +662,16 @@ printk (KERN_WARNING PRINTK_HEADER "Cannot unregister from major no %d, rc = %d\n", major, rc); return rc; + } else { + major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; } - if (major_info->gendisk.major > 128) + /* Delete the new major info from dasd_major_info if needed */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { + spin_lock_irqsave (&dasd_major_lock, flags); + list_del(&major_info->list); + spin_unlock_irqrestore (&dasd_major_lock, flags); kfree (major_info); + } return rc; } @@ -655,16 +683,18 @@ static inline dasd_device_t * dasd_device_from_kdev (kdev_t kdev) { - major_info_t *major_info = dasd_major_info; + major_info_t *major_info = NULL; + struct list_head *l; unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); - while (major_info && - major_info->gendisk.major != MAJOR (kdev)) { - major_info = major_info->next; + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); + if ( major_info->gendisk.major == MAJOR(kdev) ) + break; } spin_unlock_irqrestore (&dasd_major_lock, flags); - if (major_info) + if (major_info != &dasd_major_info[0]) return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS]; return NULL; } @@ -678,13 +708,14 @@ static inline dasd_device_t ** dasd_device_from_devno (int devno) { - major_info_t *major_info = dasd_major_info; + major_info_t *major_info; + struct list_head *l; int devindex = dasd_devindex_from_devno (devno); unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); - for (major_info = dasd_major_info; major_info; - major_info = major_info->next) { + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); if (devindex < DASD_PER_MAJOR) { spin_unlock_irqrestore (&dasd_major_lock, flags); return &major_info->dasd_device[devindex]; @@ -867,7 +898,7 @@ ccw_req_t *prev; if (cqr == NULL) - BUG (); + BUG (); if (cqr == q->head) { q->head = cqr->next; @@ -1111,20 +1142,11 @@ static inline void dasd_end_request (struct request *req, int uptodate) { - struct buffer_head *bh; - while ((bh = req->bh) != NULL) { - int nsect = bh->b_size >> 9; - blk_finished_io (nsect); - req->bh = bh->b_reqnext; - bh->b_reqnext = NULL; - bh->b_end_io (bh, uptodate); - } - if (!end_that_request_first (req, uptodate, DASD_NAME)) { + while (end_that_request_first (req, uptodate, DASD_NAME)) {} #ifndef DEVICE_NO_RANDOM - add_blkdev_randomness (MAJOR (req->rq_dev)); + add_blkdev_randomness (MAJOR (req->rq_dev)); #endif - end_that_request_last (req); - } + end_that_request_last (req); return; } @@ -1151,9 +1173,10 @@ int rc = 0; asm volatile ("STCK %0":"=m" (now)); - if ( cqr->expires + cqr->startclk < now) { + if ( cqr->expires && + cqr->expires + cqr->startclk < now) { DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device), - "IO timeout 0x%08lx%08lx usecs with req %p\n", + "IO timeout 0x%08lx%08lx usecs in req %p\n", (long) (cqr->expires >> 44), (long) (cqr->expires >> 12), cqr); cqr->expires <<=1; @@ -1170,7 +1193,6 @@ dasd_finalize_request (ccw_req_t * cqr) { dasd_device_t *device = cqr->device; - dasd_discipline_t *discipline = device->discipline; asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->req) { @@ -1225,9 +1247,11 @@ CQR_STATUS_FAILED); continue; } else { - dasd_chanq_enq_head (qp, erp_cqr); + if (erp_cqr != qp->head){ + dasd_chanq_enq_head (qp, erp_cqr); + } /* chain of completed requests is now broken */ - break; + continue; } } else if ( qp -> head -> refers ) { /* we deal with an ERP */ char *uptodatestr; @@ -1266,7 +1290,8 @@ for (temp = cqr; temp != NULL ;temp=temp-> next ) if ( temp ->status == CQR_STATUS_QUEUED) chanq_max_size --; - while ( (! list_empty(&queue->queue_head)) && + while ( (! queue->plugged) && + (! list_empty(&queue->queue_head)) && (req=dasd_next_request(queue)) != NULL) { /* queue empty or certain critera fulfilled -> transfer */ if ( qp -> head == NULL || @@ -1307,6 +1332,10 @@ /* to be filled with MIH */ } break; + + case CQR_STATUS_PENDING: + /* just wait */ + break; default: BUG(); } @@ -1390,8 +1419,54 @@ } #endif /* LINUX_IS_24 */ +/* + * DASD_HANDLE_STATE_CHANGE_PENDING + * + * DESCRIPTION + * Handles the state change pending interrupt. + * Search for the device related request queue and check if the first + * cqr in queue in in status 'CQR_STATUE_PENDING'. + * If so the status is set to 'CQR_STATUS_QUEUED' to reactivate + * the device. + * + * PARAMETER + * stat device status of state change pending interrupt. + */ +void +dasd_handle_state_change_pending (devstat_t *stat) +{ + dasd_device_t **device_addr; + ccw_req_t *cqr; + + device_addr = dasd_device_from_devno (stat->devno); + + if (device_addr == NULL) { + printk (KERN_INFO PRINTK_HEADER + "unable to find device for state change pending " + "interrupt: devno%04X\n", + stat->devno); + } else { + /* re-activate first request in queue */ + cqr = (*device_addr)->queue.head; + + if (cqr->status == CQR_STATUS_PENDING) { + + DASD_MESSAGE (KERN_INFO, (*device_addr), + "%s", + "device request queue restarted by " + "state change pending interrupt\n"); + + del_timer(&(*device_addr)->timer); + + check_then_set(&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); + dasd_schedule_bh(*device_addr); + } + } +} /* end dasd_handle_state_change_pending */ /* * function dasd_int_handler @@ -1406,7 +1481,7 @@ dasd_device_t *device; unsigned long long now; #ifdef ERP_DEBUG - static int counter; + static int counter = 0; #endif dasd_era_t era = dasd_era_none; /* default is everything is okay */ devstat_t *stat = (devstat_t *)ds; @@ -1415,6 +1490,16 @@ if (stat == NULL) { BUG(); } + + /* first of all check for state change pending interrupt */ + if (stat->dstat & (DEV_STAT_ATTENTION | + DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP )) { + + dasd_handle_state_change_pending (stat); + //return; /* TBD */ + } + ip = stat->intparm; if (!ip) { /* no intparm: unsolicited interrupt */ printk (KERN_INFO PRINTK_HEADER @@ -1441,11 +1526,35 @@ BUG(); } #ifdef ERP_DEBUG - counter++; - if ( counter % 137 == 0 ) { - stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; - stat->cstat = 0x00; - stat->dstat = 0x02; + if ((++counter % 937 >= 0) && + ( counter % 937 <= 10) && + ( counter < 5000 ) && + ( counter > 2000 ) ){ + static int fake_count = 0; + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); + printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count); + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); + era = dasd_era_recover; + stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; + stat->dstat |= 0x02; +// sense 32 + { + char *sense = stat->ii.sense.data; + sense [25] = 0x1D; + sense [27] = 0x00; + //sense [25] = (fake_count % 256); //0x1B; + //sense [27] = 0x00; + } +// sense 24 +// { +// char *sense = stat->ii.sense.data; +// sense [0] = (counter % 0xFF); //0x1B; +// sense [1] = ((counter * 7) % 0xFF); //0x1B; +// sense [2] = (fake_count % 0xFF); //0x1B; +// sense [27] = 0x80; +// } + +/* memset(stat->ii.sense.data,0,32); stat->ii.sense.data[2] = 0x06; stat->ii.sense.data[4] = 0x04; @@ -1464,6 +1573,7 @@ stat->ii.sense.data[24] = 0x04; stat->ii.sense.data[25] = 0x10; stat->ii.sense.data[26] = 0x4e; +*/ } #endif /* first of all lets try to find out the appropriate era_action */ @@ -1545,13 +1655,13 @@ ccw_req_t * default_erp_action (ccw_req_t * cqr) { - ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0); + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); printk (KERN_WARNING PRINTK_HEADER "Default ERP called... \n"); - if (!erp) - return NULL; + if (erp == NULL) + return NULL; erp->cpaddr->cmd_code = CCW_CMD_TIC; erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr; @@ -1562,6 +1672,7 @@ erp->retries = 16; erp->status = CQR_STATUS_FILLED; + return erp; } @@ -1582,8 +1693,8 @@ ccw_req_t * default_erp_postaction (ccw_req_t * erp) { + ccw_req_t *cqr = NULL, *free_erp = NULL; dasd_device_t *device = NULL; - ccw_req_t *free_erp; int success; device = (dasd_device_t *) (erp->device); @@ -1593,6 +1704,24 @@ else success = 0; +#ifdef ERP_DEBUG + + /* print current erp_chain */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP postaction called for erp chain:\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p with erp function %p\n", + temp_erp, + temp_erp->refers, + temp_erp->function ); + } + } + +#endif /* ERP_DEBUG*/ + if (erp->refers == NULL || erp->function == NULL) { BUG(); } @@ -1606,39 +1735,46 @@ while (erp->refers != NULL) { free_erp = erp; erp = erp->refers; + /* remove the request from the device queue */ dasd_chanq_deq (&device->queue, free_erp); + /* free the finished erp request */ dasd_free_request (free_erp); } /* save ptr to original cqr */ + cqr = erp; + +#ifdef ERP_DEBUG + printk (KERN_INFO PRINTK_HEADER + "default_erp_postaction - left original request = %p \n",cqr); +#endif /* ERP_DEBUG */ - /* - * printk (KERN_INFO PRINTK_HEADER - * "default_erp_postaction - left original request = %p \n",erp); - */ /* set corresponding status to original cqr */ if (success) { - check_then_set (&erp->status, CQR_STATUS_ERROR, + check_then_set (&cqr->status, + CQR_STATUS_ERROR, CQR_STATUS_DONE); } else { - check_then_set (&erp->status, CQR_STATUS_ERROR, + check_then_set (&cqr->status, + CQR_STATUS_ERROR, CQR_STATUS_FAILED); } - + +#ifdef ERP_DEBUG /* print current erp_chain */ -#if 0 printk (KERN_WARNING PRINTK_HEADER "default ERP postaction finished with remaining chain:\n"); { ccw_req_t *temp_erp = NULL; - for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) { + for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { printk (KERN_WARNING PRINTK_HEADER " erp %p refers to %p \n", temp_erp, temp_erp->refers); } } -#endif - return erp; +#endif /* ERP_DEBUG */ + + return cqr; } /* end default_erp_postaction */ /* SECTION: The helpers of the struct file_operations */ @@ -1655,6 +1791,7 @@ dasd_format (dasd_device_t * device, format_data_t * fdata) { int rc = 0; + int format_done = 0; ccw_req_t *req = NULL; format_data_t temp = { @@ -1663,29 +1800,41 @@ fdata->blksize, fdata->intensity }; - + + spin_lock (&dasd_open_count_lock); if (device->open_count != 1) { DASD_MESSAGE (KERN_INFO, device, "device is already open %d times", device->open_count); + spin_unlock(&dasd_open_count_lock); return -EINVAL; } if (!device->discipline->format_device) { + spin_unlock(&dasd_open_count_lock); return -EINVAL; } + device->open_count = -1; + spin_unlock (&dasd_open_count_lock); /* downgrade state of the device */ dasd_set_device_level (device->devinfo.irq, DASD_DEVICE_LEVEL_RECOGNIZED, device->discipline, 0); - DASD_MESSAGE (KERN_INFO, device, "Starting format from %d to %d (%d B blocks flags %d",fdata->start_unit,fdata->stop_unit,fdata->blksize,fdata->intensity); + DASD_MESSAGE (KERN_INFO, device, + "Starting format from %d to %d (%d B blocks flags %d", + fdata->start_unit, + fdata->stop_unit, + fdata->blksize, + fdata->intensity); /* Invalidate first track */ if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT && - fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && - fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { + fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { format_data_t temp2 = - {0, 0, DASD_FORMAT_DEFAULT_BLOCKSIZE, 0x04}; - DASD_MESSAGE (KERN_INFO, device, "%s", "Invalidating first track..."); + {0, 0, fdata->blksize, 0x04}; + DASD_MESSAGE (KERN_INFO, device, + "%s", + "Invalidating first track..."); req = device->discipline->format_device (device, &temp2); if (req) { rc = sleep_on_req (req); @@ -1694,32 +1843,43 @@ rc = -EINVAL; } if (rc) { - printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n"); - } + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Can't invalidate Track 0\n"); + } else { + DASD_MESSAGE (KERN_INFO, device, + "%s", + "...Invalidation complete"); + } temp.start_unit++; - DASD_MESSAGE (KERN_INFO, device, "%s", "...Invalidation complete"); } /* format remainnig tracks of device */ - while (!rc && - ((req = device->discipline->format_device (device, &temp)) != - NULL)) { + while (!rc && + ((req = device->discipline->format_device (device, &temp)) != NULL) ) { + format_done=1; if ((rc = sleep_on_req (req)) != 0) { + + DASD_MESSAGE (KERN_WARNING, device, " Formatting failed with rc = %d\n", rc); break; } + dasd_free_request (req); /* request is no longer used */ temp.start_unit++; } - if (!rc && - req == NULL) { + + if (!rc && + req == NULL ) { if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT && - fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && - fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { + fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { format_data_t temp2 = {0, 0, fdata->blksize, fdata->intensity}; - DASD_MESSAGE (KERN_INFO, device, "%s", "Revalidating first track..."); + DASD_MESSAGE (KERN_INFO, device, + "%s", + "Revalidating first track..."); req = device->discipline->format_device (device, &temp2); if (req) { rc = sleep_on_req (req); @@ -1728,12 +1888,22 @@ rc = -EINVAL; } if (rc) { - printk (KERN_WARNING PRINTK_HEADER - "Can't revalidate Track 0\n"); - } - DASD_MESSAGE (KERN_INFO, device, "%s", "...Revalidation complete"); + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Can't revalidate Track 0\n"); + } else { + DASD_MESSAGE (KERN_INFO, device, + "%s", + "...Revalidation complete"); + } } } /* end if no more requests */ + + /* check if at least one format cp was build in discipline */ + if (!format_done) { + rc = -EINVAL; + } + if (rc) DASD_MESSAGE (KERN_WARNING, device, "%s", " Formatting finished unsuccessfully"); @@ -1741,22 +1911,75 @@ DASD_MESSAGE (KERN_INFO, device, "%s", " Formatting finished successfully"); - /* re-activate device even if formatting was unsuccessful */ - /* Horst Hummel - 17/10/00 - ITPM PL020062RSC */ - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - device->discipline, - 0); - udelay (1500000); - - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_ANALYSED, - device->discipline, - 0); - + /* + * re-analyse device + */ + dasd_set_device_level (device->devinfo.irq, + DASD_DEVICE_LEVEL_ONLINE, + device->discipline, + 0); + udelay (1500000); + + dasd_set_device_level (device->devinfo.irq, + DASD_DEVICE_LEVEL_ONLINE, + device->discipline, + 0); + + spin_lock (&dasd_open_count_lock); + device->open_count=1; + spin_unlock (&dasd_open_count_lock); return rc; } /* end dasd_format */ +static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls); + +static dasd_ioctl_list_t * +dasd_find_ioctl( int no ) +{ + struct list_head *curr; + list_for_each(curr,&dasd_ioctls){ + if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){ + return list_entry(curr,dasd_ioctl_list_t,list); + } + } + return NULL; +} + +int +dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler ) +{ + dasd_ioctl_list_t *new; + if (dasd_find_ioctl(no)) + return -EBUSY; + new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL); + if ( new == NULL ) + return -ENOMEM; + new -> no = no; + new -> handler = handler; + list_add(&new->list,&dasd_ioctls); +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +int +dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler ) +{ + dasd_ioctl_list_t *old = dasd_find_ioctl(no); + if ( old == NULL ) + return -ENOENT; + if ( old->no != no || + old->handler != handler ) + return -EINVAL; + list_del(&old->list); + kfree(old); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + static int do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) { @@ -1809,10 +2032,11 @@ break; } case HDIO_GETGEO:{ - struct hd_geometry geo = - {0,}; - if (device->discipline->fill_geometry) - device->discipline->fill_geometry (device, &geo); + struct hd_geometry geo = {0,}; + rc = dasd_fillgeo(inp->i_rdev, &geo); + if (rc) + break; + rc = copy_to_user ((struct hd_geometry *) data, &geo, sizeof (struct hd_geometry)); if (rc) @@ -1944,17 +2168,23 @@ break; } default:{ - DASD_MESSAGE (KERN_INFO, device, - "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n", - no, - _IOC_DIR (no) == _IOC_NONE ? "0" : - _IOC_DIR (no) == _IOC_READ ? "r" : - _IOC_DIR (no) == _IOC_WRITE ? "w" : - _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? - "rw" : "u", - _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no), - data); - rc = -EINVAL; + + dasd_ioctl_list_t *old = dasd_find_ioctl(no); + if ( old ) { + rc = old->handler(inp,no,data); + } else { + DASD_MESSAGE (KERN_INFO, device, + "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n", + no, + _IOC_DIR (no) == _IOC_NONE ? "0" : + _IOC_DIR (no) == _IOC_READ ? "r" : + _IOC_DIR (no) == _IOC_WRITE ? "w" : + _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? + "rw" : "u", + _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no), + data); + rc = -EINVAL; + } break; } } @@ -2000,10 +2230,16 @@ " %s", " Cannot open unrecognized device\n"); return -EINVAL; } + spin_lock(&dasd_open_count_lock); + if (device->open_count == -1) { + spin_unlock (&dasd_open_count_lock); + return -EBUSY; + } #ifdef MODULE MOD_INC_USE_COUNT; #endif /* MODULE */ device->open_count++; + spin_unlock (&dasd_open_count_lock); return rc; } @@ -2023,6 +2259,7 @@ MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); return -EINVAL; } + spin_lock(&dasd_open_count_lock); if (device->open_count--) { #ifdef MODULE MOD_DEC_USE_COUNT; @@ -2031,6 +2268,7 @@ fsync_dev(inp->i_rdev); /* sync the device */ if (device->open_count == 0) /* finally invalidate buffers */ invalidate_buffers(inp->i_rdev); + spin_unlock(&dasd_open_count_lock); return rc; } @@ -2048,6 +2286,26 @@ }; /* SECTION: Management of device list */ +int +dasd_fillgeo(int kdev,struct hd_geometry *geo) +{ + dasd_device_t *device = dasd_device_from_kdev (kdev); + if (!device->discipline->fill_geometry) + return -EINVAL; + + device->discipline->fill_geometry (device, geo); + geo->start = device->major_info-> + gendisk.part[MINOR(kdev)].start_sect; + + /* This is a hack. dasdfmt and ibm.c expect geo.start + to contain the block number of the label block when + it calls HDIO_GETGEO on the first partition. */ + if (geo->start == 0) + geo->start = device->sizes.pt_block; + + return 0; +} + /* This one is needed for naming 18000+ possible dasd devices */ int @@ -2057,27 +2315,30 @@ char first, second, third; if (hd) { - major_info_t *major_info; - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { + major_info_t *major_info=NULL; + struct list_head *l; + + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); if (&major_info->gendisk == hd) { break; } index += DASD_PER_MAJOR; } - if (major_info == NULL) { + if (major_info == &dasd_major_info[0]) { return -EINVAL; } } third = index % 26; - second = (index / 26) % 27; - first = ((index / 26) / 27) % 27; + second = ((index-26) / 26) % 26; + first = (((index-702) / 26) / 26) % 26; len = sprintf (str, "dasd"); - if (first) { - len += sprintf (str + len, "%c", first + 'a' - 1); + if (index>701) { + len += sprintf (str + len, "%c", first + 'a'); } - if (second) { - len += sprintf (str + len, "%c", second + 'a' - 1); + if (index>25) { + len += sprintf (str + len, "%c", second + 'a'); } len += sprintf (str + len, "%c", third + 'a'); if (partition) { @@ -2093,13 +2354,28 @@ #ifdef CONFIG_DASD_DYNAMIC static void +dasd_plug_device (dasd_device_t *device) +{ + device->request_queue.plugged = 1; /* inhibit further calls of request_fn */ +} + +static void +dasd_unplug_device (dasd_device_t *device) +{ + generic_unplug_device(&device->request_queue); +} + +static void dasd_not_oper_handler (int irq, int status) { dasd_device_t *device = NULL; - major_info_t *major_info; + major_info_t *major_info = NULL; + struct list_head *l; int i, devno = -ENODEV; - for (major_info = dasd_major_info; major_info != NULL; major_info = major_info->next) { + /* find out devno of leaving device: CIO has already deleted this information ! */ + list_for_each(l,&dasd_major_info[0].list) { + major_info=list_entry(l, major_info_t,list); for (i = 0; i < DASD_PER_MAJOR; i++) { device = major_info->dasd_device[i]; if (device && @@ -2116,20 +2392,24 @@ "not_oper_handler called on irq %d no devno!\n", irq); return; } - printk (KERN_INFO PRINTK_HEADER - "not_oper_handler called on irq %d devno %04X\n", irq, devno); + if (device->open_count != 0) { - printk (KERN_ALERT PRINTK_HEADER - "Device %04X detached has still been open. expect errors\n", devno); - } - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0); + DASD_MESSAGE(KERN_ALERT,device,"%s", + "open device has gone. please repair!"); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, + NULL, 0); + } else { + DASD_MESSAGE(KERN_INFO,device,"%s","device has gone"); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, + NULL, 0); + } } static int dasd_enable_single_volume (int irq) { int rc = 0; - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); printk (KERN_INFO PRINTK_HEADER "waiting for response...\n"); { @@ -2137,8 +2417,7 @@ init_waitqueue_head (&wait_queue); interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1); } - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, - NULL, 0); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); return rc; } @@ -2148,12 +2427,13 @@ int devno; int rc; devno = get_devno_by_irq (irq); - if (devno == -ENODEV) + printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n"); + if (devno == -ENODEV) { + printk (KERN_WARNING PRINTK_HEADER "NODEV\n"); return -ENODEV; + } if (dasd_autodetect) { dasd_add_range (devno, 0); - } else { - return -ENODEV; } rc = dasd_enable_single_volume (irq); return rc; @@ -2172,14 +2452,26 @@ dasd_device_t **device_addr, *device; int current_level; major_info_t *major_info = NULL; + struct list_head *l; int i, minor, major; ccw_req_t *cqr = NULL; struct gendisk *dd; devno = get_devno_by_irq (irq); - if (devno < 0) { - printk (KERN_WARNING PRINTK_HEADER " no device appears to be connected to SCH %d\n", irq); - return -ENODEV; + if (devno < 0) { /* e.g. when device has been detached before */ + /* search in device list */ + list_for_each(l,&dasd_major_info[0].list) { + major_info = list_entry(l,major_info_t,list); + for (i = 0; i < DASD_PER_MAJOR; i++) { + device = major_info->dasd_device[i]; + if (device && device->devinfo.irq == irq) { + devno = device->devinfo.devno; + break; + } + } + if (devno == -ENODEV) + return -ENODEV; + } } if (dasd_devindex_from_devno (devno) < 0) { return -ENODEV; @@ -2204,8 +2496,9 @@ memset (device, 0, sizeof (dasd_device_t)); *device_addr = device; } - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { + list_for_each(l,&dasd_major_info[0].list) { int i; + major_info = list_entry(l,major_info_t,list); for (i = 0; i < DASD_PER_MAJOR; i++) { if (major_info->dasd_device[i] == device) { device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS); @@ -2215,21 +2508,21 @@ if (i < DASD_PER_MAJOR) break; } - if (major_info == NULL) { + if (major_info == &dasd_major_info[0]) { return -ENODEV; } - device->major_info = major_info; - dasd_device_name (device->name, - ((long) device_addr - - (long) device->major_info->dasd_device) / - sizeof (dasd_device_t *), - 0, &major_info->gendisk); minor = MINOR (device->kdev); major = MAJOR (device->kdev); current_level = device->level; if (desired_level > current_level) { switch (current_level) { case DASD_DEVICE_LEVEL_UNKNOWN: /* Find a discipline */ + device->major_info = major_info; + dasd_device_name (device->name, + ((long) device_addr - + (long) device->major_info->dasd_device) / + sizeof (dasd_device_t *), + 0, &major_info->gendisk); rc = get_dev_info_by_irq (irq, &device->devinfo); if (rc < 0) { break; @@ -2242,6 +2535,9 @@ break; } device->discipline = discipline; + device->debug_area = debug_register(device->name,0,2,3*sizeof(long)); + debug_register_view(device->debug_area,&debug_sprintf_view); + debug_register_view(device->debug_area,&debug_hex_ascii_view); if (device->discipline->int_handler) { #ifdef CONFIG_DASD_DYNAMIC s390_request_irq_special (irq, @@ -2276,8 +2572,6 @@ } } init_waitqueue_head (&device->wait_q); - blk_init_queue (&device->request_queue, do_dasd_request); - blk_queue_headactive (&device->request_queue, 0); check_then_set (&device->level, DASD_DEVICE_LEVEL_UNKNOWN, DASD_DEVICE_LEVEL_RECOGNIZED); @@ -2325,9 +2619,12 @@ return -EMEDIUMTYPE; } } + blk_init_queue (&device->request_queue, do_dasd_request); + blk_queue_headactive (&device->request_queue, 0); + elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP); for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - if (i == 0) - blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; + if (i == 0) + blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; else blk_size[major][minor + i] = 0; hardsect_size[major][minor + i] = device->sizes.bp_block; @@ -2336,7 +2633,7 @@ blksize_size[major][minor + i] = 1024; max_sectors[major][minor + i] = - 255 << device->sizes.s2b_shift; + device->discipline->max_blocks << device->sizes.s2b_shift; } check_then_set (&device->level, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, @@ -2344,6 +2641,12 @@ dd = &major_info->gendisk; dd->sizes[minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; + dd->part[minor].start_sect = 0; + { + char buffer[5]; + sprintf(buffer,"%04X",device->devinfo.devno); + dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL); + } #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) #ifndef MODULE if (flags & 0x80) @@ -2353,8 +2656,15 @@ if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) break; case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ - - break; + dasd_unplug_device(device); + check_then_set (&device->level, + DASD_DEVICE_LEVEL_ANALYSED, + DASD_DEVICE_LEVEL_ONLINE); + + if (desired_level == DASD_DEVICE_LEVEL_ONLINE) + break; + case DASD_DEVICE_LEVEL_ONLINE: + break; default: printk (KERN_WARNING PRINTK_HEADER "Internal error in " __FILE__ " on line %d." @@ -2368,20 +2678,29 @@ } } else if (desired_level < current_level) { /* donwgrade device status */ switch (current_level) { - case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ + case DASD_DEVICE_LEVEL_ONLINE: /* Fallthrough ?? */ + dasd_plug_device(device); check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSED, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED) - break; - case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: + DASD_DEVICE_LEVEL_ONLINE, + DASD_DEVICE_LEVEL_ANALYSED); + if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) + break; + case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - blk_size[major][minor] = 0; + __invalidate_buffers(MKDEV(major,minor),1); + blk_size[major][minor] = 0; hardsect_size[major][minor + i] = 0; blksize_size[major][minor + i] = 0; max_sectors[major][minor + i] = 0; } memset (&device->sizes, 0, sizeof (dasd_sizes_t)); + blk_cleanup_queue (&device->request_queue); + check_then_set (&device->level, + DASD_DEVICE_LEVEL_ANALYSED, + DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); + if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED) + break; + case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: check_then_set (&device->level, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, DASD_DEVICE_LEVEL_ANALYSIS_PENDING); @@ -2398,10 +2717,12 @@ free_irq (irq, &device->dev_status); } device->discipline = NULL; - blk_cleanup_queue (&device->request_queue); + debug_unregister(device->debug_area); check_then_set (&device->level, DASD_DEVICE_LEVEL_RECOGNIZED, DASD_DEVICE_LEVEL_UNKNOWN); + *device_addr = NULL; + kfree(device); if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN) break; case DASD_DEVICE_LEVEL_UNKNOWN: @@ -2433,6 +2754,13 @@ int len; } tempinfo_t; +void dasd_fill_inode (struct inode* inode, int fill) { + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct proc_dir_entry *dasd_proc_root_entry = NULL; #else @@ -2445,7 +2773,8 @@ nlink:1, uid:0, gid:0, - size:0 + size:0, + fill_inode:dasd_fill_inode }; #endif /* KERNEL_VERSION */ static struct proc_dir_entry *dasd_devices_entry; @@ -2458,7 +2787,9 @@ int size = 1; int len = 0; major_info_t *temp = dasd_major_info; + struct list_head *l; tempinfo_t *info; + int i; info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t)); if (info == NULL) { @@ -2467,15 +2798,14 @@ } else { file->private_data = (void *) info; } - while (temp) { - int i; + list_for_each(l,&dasd_major_info[0].list) { + temp = list_entry(l,major_info_t,list); for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { dasd_device_t *device = temp->dasd_device[i]; if (device) { size += 128; } } - temp = temp->next; } temp = dasd_major_info; info->data = (char *) vmalloc (size); /* FIXME! determine space needed in a better way */ @@ -2484,8 +2814,8 @@ vfree (info); return -ENOMEM; } - while (temp) { - int i; + list_for_each(l,&dasd_major_info[0].list) { + temp = list_entry(l,major_info_t,list); for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { dasd_device_t *device = temp->dasd_device[i]; if (device) { @@ -2519,15 +2849,24 @@ device->sizes.blocks, ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); break; + case DASD_DEVICE_LEVEL_ONLINE: + len += sprintf (info->data + len, "active "); + len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n", + device->sizes.bp_block, + device->sizes.blocks, + ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); + break; default: len += sprintf (info->data + len, "no stat\n"); break; } } } - temp = temp->next; } info->len = len; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return rc; } @@ -2554,6 +2893,11 @@ dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset) { char *buffer = vmalloc (user_len); + int off = 0; + char *temp; + int irq; + int j,target; + dasd_range_t *rptr, range; if (buffer == NULL) return -ENOMEM; @@ -2563,17 +2907,68 @@ } buffer[user_len] = 0; printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer); - if (!strncmp (buffer, "add range", strlen ("add_range"))) { - - } else if (!strncmp (buffer, "enable device", strlen ("enable device"))) { - - } else if (!strncmp (buffer, "disable device", strlen ("disable device"))) { - - } else { - printk (KERN_WARNING PRINTK_HEADER "unknown command %s", - buffer); - } - vfree (buffer); + if (strncmp ( buffer, "set ",4) && + strncmp ( buffer, "add ",4)){ + printk (KERN_WARNING PRINTK_HEADER + "/proc/dasd/devices: only 'set' and 'add' are supported verbs"); + return -EINVAL; + } + off += 4; + while (!isalnum(buffer[off])) off++; + if (!strncmp (buffer + off, "device", strlen ("device"))) { + off += strlen("device"); + while (!isalnum(buffer[off])) off++; + } + if (!strncmp (buffer + off, "range=", strlen ("range="))) { + off += strlen("range="); + while (!isalnum(buffer[off])) off++; + } + temp = buffer+off; + range.from = dasd_strtoul (temp, &temp); + range.to = range.from; + if (*temp == '-') { + temp++; + range.to = dasd_strtoul (temp, &temp); + } + off = (long)temp - (long)buffer; + if ( !strncmp ( buffer, "add",strlen("add"))) { + rptr = dasd_add_range (range.from, range.to); + } else { + rptr = ⦥ + } + while (!isalnum(buffer[off])) off++; + printk (KERN_INFO PRINTK_HEADER + "varying device range %04X-%04X\n", rptr->from, rptr->to); + if ( !strncmp ( buffer, "add",strlen("add")) || + !strncmp ( buffer+off, "on",strlen("on")) ) { + target = DASD_DEVICE_LEVEL_ONLINE; + for (j = rptr->from; j <= rptr->to; j++) { + irq = get_irq_by_devno (j); + if (irq >= 0) { + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); + } + } + printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); + { + static wait_queue_head_t wait_queue; + init_waitqueue_head (&wait_queue); + interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) ); + } + } else if ( !strncmp ( buffer+off, "off",strlen("off"))) { + target = DASD_DEVICE_LEVEL_UNKNOWN; + } else { + printk (KERN_WARNING PRINTK_HEADER + "/proc/dasd/devices: parse error in '%s'", buffer); + vfree (buffer); + return -EINVAL; + + } + for (j = rptr->from; j <= rptr->to; j++) { + irq = get_irq_by_devno (j); + if (irq >= 0) { + dasd_set_device_level (irq, target, NULL, 0); + } + } return user_len; } @@ -2587,6 +2982,9 @@ vfree (p_info->data); vfree (p_info); } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif return rc; } @@ -2693,6 +3091,9 @@ } len += sprintf (info->data + len, "\n"); info->len = len; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return rc; } @@ -2779,26 +3180,44 @@ } /* SECTION: Initializing the driver */ - int __init dasd_init (void) { int rc = 0; int irq; int j; - major_info_t *major_info; + major_info_t *major_info=NULL; + struct list_head *l; dasd_range_t *range; printk (KERN_INFO PRINTK_HEADER "initializing...\n"); - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { + dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long)); + debug_register_view(dasd_debug_area,&debug_sprintf_view); + debug_register_view(dasd_debug_area,&debug_hex_ascii_view); + + if ( dasd_debug_area == NULL ) { + goto failed; + } + DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY"); + dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL); + if ( dasd_devfs_handle < 0 ) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs"); + goto failed; + } + list_for_each(l,&dasd_major_info[0].list) { + major_info=list_entry(l,major_info_t,list); if ((rc = dasd_register_major (major_info)) > 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "major %d: success",major_info->gendisk.major); printk (KERN_INFO PRINTK_HEADER "Registered successfully to major no %u\n", major_info->gendisk.major); } else { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "major %d: failed",major_info->gendisk.major); printk (KERN_WARNING PRINTK_HEADER "Couldn't register successfully to major no %d\n", major_info->gendisk.major); /* revert registration of major infos */ - goto major_failed; + goto failed; } } #ifndef MODULE @@ -2809,57 +3228,77 @@ rc = dasd_proc_init (); if (rc) { - goto proc_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "%s","no proc-FS"); + goto failed; } genhd_dasd_name = dasd_device_name; + genhd_dasd_fillgeo = dasd_fillgeo; #ifdef CONFIG_DASD_ECKD rc = dasd_eckd_init (); if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "ECKD discipline %s","success"); printk (KERN_INFO PRINTK_HEADER "Registered ECKD discipline successfully\n"); } else { - goto eckd_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "ECKD discipline %s","failed"); + goto failed; } #endif /* CONFIG_DASD_ECKD */ #ifdef CONFIG_DASD_FBA rc = dasd_fba_init (); if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "FBA discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER "Registered FBA discipline successfully\n"); } else { - goto fba_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "FBA discipline %s","failed"); + goto failed; } #endif /* CONFIG_DASD_FBA */ -#ifdef CONFIG_DASD_MDSK +#ifdef CONFIG_DASD_DIAG if (MACHINE_IS_VM) { rc = dasd_diag_init (); if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "DIAG discipline %s","success"); printk (KERN_INFO PRINTK_HEADER - "Registered MDSK discipline successfully\n"); + "Registered DIAG discipline successfully\n"); } else { - goto mdsk_failed; + DASD_DRIVER_DEBUG_EVENT(1,dasd_init, + "DIAG discipline %s","failed"); + goto failed; } } -#endif /* CONFIG_DASD_MDSK */ +#endif /* CONFIG_DASD_DIAG */ rc = 0; - for (range = dasd_range_head; range; range = range->next) { - for (j = range->from; j <= range->to; j++) { - irq = get_irq_by_devno (j); - if (irq >= 0) - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - NULL, 0); - } - } - if (dasd_autodetect) { - for (irq = get_irq_first (); irq != -ENODEV; irq = get_irq_next (irq)) { + if (dasd_autodetect) { /* update device range to all devices */ + for (irq = get_irq_first (); irq != -ENODEV; + irq = get_irq_next (irq)) { int devno = get_devno_by_irq (irq); int index = dasd_devindex_from_devno (devno); if (index == -ENODEV) { /* not included in ranges */ + DASD_DRIVER_DEBUG_EVENT(2,dasd_init, + "add %04X to range", + devno); dasd_add_range (devno, 0); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - NULL, 0); - } + } + } + } + for (range = dasd_range_head; range; range = range->next) { + for (j = range->from; j <= range->to; j++) { + irq = get_irq_by_devno (j); + if (irq >= 0) + DASD_DRIVER_DEBUG_EVENT(2,dasd_init, + "1st step in initialization irq 0x%x",irq); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, + NULL, 0); } } printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); @@ -2873,99 +3312,117 @@ for (j = range->from; j <= range->to; j++) { irq = get_irq_by_devno (j); if (irq >= 0) { - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, + DASD_DRIVER_DEBUG_EVENT(2,dasd_init, + "2nd step in initialization irq 0x%x",irq); + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); } } } - goto out; -#ifdef CONFIG_DASD_MDSK - mdsk_failed: - dasd_diag_cleanup (); -#endif /* CONFIG_DASD_MDSK */ -#ifdef CONFIG_DASD_FBA - fba_failed: - dasd_fba_cleanup (); -#endif /* CONFIG_DASD_FBA */ -#ifdef CONFIG_DASD_ECKD - eckd_failed: - dasd_eckd_cleanup (); -#endif /* CONFIG_DASD_ECKD */ - proc_failed: - dasd_proc_cleanup (); - major_failed:{ - major_info_t * temp; - for (temp = dasd_major_info; - temp && (temp != major_info); - temp = temp->next) { - dasd_unregister_major (temp); - } - } - dasd_cleanup_emergency_req (); + goto out; + failed: printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); - out: + cleanup_dasd(); + out: + DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE"); printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); return rc; } -void +static void cleanup_dasd (void) { - int j, rc = 0; + int i,j,rc; int irq; - major_info_t *major_info; + major_info_t *major_info=NULL; + struct list_head *l; dasd_range_t *range, *next; printk (KERN_INFO PRINTK_HEADER "shutting down\n"); - - dasd_proc_cleanup (); - + DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY"); for (range = dasd_range_head; range; range = range->next) { for (j = range->from; j <= range->to; j++) { irq = get_irq_by_devno (j); if (irq >= 0) { + DASD_DRIVER_DEBUG_EVENT(2,"cleanup_dasd", + "shutdown irq 0x%x",irq); dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0); } } } - for (major_info = dasd_major_info; major_info; major_info = major_info->next) { - int i; +#ifdef CONFIG_DASD_DIAG + if (MACHINE_IS_VM) { + dasd_diag_cleanup (); + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "DIAG discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered DIAG discipline successfully\n"); + } +#endif /* CONFIG_DASD_DIAG */ +#ifdef CONFIG_DASD_FBA + dasd_fba_cleanup (); + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "FBA discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered FBA discipline successfully\n"); +#endif /* CONFIG_DASD_FBA */ +#ifdef CONFIG_DASD_ECKD + dasd_eckd_cleanup (); + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "ECKD discipline %s","success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered ECKD discipline successfully\n"); +#endif /* CONFIG_DASD_ECKD */ + + dasd_proc_cleanup (); + dasd_cleanup_emergency_req (); + + list_for_each(l,&dasd_major_info[0].list) { + major_info=list_entry(l,major_info_t,list); for (i = 0; i < DASD_PER_MAJOR; i++) { kfree (major_info->dasd_device[i]); } - if ((rc = dasd_unregister_major (major_info)) == 0) { + if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) && + (rc = dasd_unregister_major (major_info)) == 0) { + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "major %d: success",major_info->gendisk.major); printk (KERN_INFO PRINTK_HEADER "Unregistered successfully from major no %u\n", major_info->gendisk.major); } else { + DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", + "major %d: failed",major_info->gendisk.major); printk (KERN_WARNING PRINTK_HEADER "Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc); } } - dasd_cleanup_emergency_req (); + range = dasd_range_head; while (range) { next = range->next; - kfree (range); + dasd_remove_range (range); if (next == NULL) break; else range = next; } dasd_range_head = NULL; + +#ifndef MODULE + for( j = 0; j < 256; j++ ) + if ( dasd[j] ) { + kfree(dasd[j]); + dasd[j] = NULL; + } +#endif /* MODULE */ + if (dasd_devfs_handle) + devfs_unregister(dasd_devfs_handle); + if (dasd_debug_area != NULL ) + debug_unregister(dasd_debug_area); -#ifdef CONFIG_DASD_DYNAMIC - { - dasd_devreg_t *reg; - while (dasd_devreg_head) { - reg = dasd_devreg_head->next; - kfree (dasd_devreg_head); - dasd_devreg_head = reg; - } - } -#endif /* CONFIG_DASD_DYNAMIC */ printk (KERN_INFO PRINTK_HEADER "shutdown completed\n"); + DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE"); } #ifdef MODULE diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c --- v2.4.3/linux/drivers/s390/block/dasd_3990_erp.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/dasd_3990_erp.c Wed Apr 11 19:02:28 2001 @@ -1,46 +1,196 @@ /* * File...........: linux/drivers/s390/block/dasd_3990_erp.c - * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Horst Hummel <Horst.Hummel@de.ibm.com> + * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com> + * Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 */ #include <asm/ccwcache.h> +#include <asm/idals.h> #include <asm/dasd.h> +#include <asm/s390io.h> +#include <linux/timer.h> +#include "dasd_eckd.h" +#include "dasd_3990_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER -#define PRINTK_HEADER "dasd_erp(3990)" -#endif /* PRINTK_HEADER */ +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd_erp(3990): " /* - * DASD_3990_ERP_EXAMINE_32 - * - * DESCRIPTION - * Checks only for fatal/no/recoverable error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for recoverable others. + ***************************************************************************** + * SECTION DEBUG ROUTINES + ***************************************************************************** */ -dasd_era_t -dasd_3990_erp_examine_32 (char *sense) +#ifdef ERP_DEBUG +void +log_erp_chain (ccw_req_t *cqr, + int caller, + __u32 cpa) { - switch (sense[25]) { - case 0x00: - return dasd_era_none; - case 0x01: - return dasd_era_fatal; - default: - return dasd_era_recover; - } + ccw_req_t *loop_cqr = cqr; + dasd_device_t *device = cqr->device; -} /* end dasd_3990_erp_examine_32 */ + char *page = (char *)get_free_page(GFP_ATOMIC); + int len = 0; + int i; + char *nl, + *end_cqr, + *begin, + *end; + + if ( page == NULL ) { + printk (KERN_WARNING PRINTK_HEADER + "No memory to dump ERP chain\n"); + return; + } + + while (loop_cqr != NULL) { + + memset (page, 0, 4096); + len = 0; + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "device %04X on irq %d: (%s) ERP chain report for req: %p\n", + device->devinfo.devno, + device->devinfo.irq, + caller == 0 ? "EXAMINE" : "ACTION", + loop_cqr); + + nl = (char *) loop_cqr; + end_cqr = nl + sizeof (ccw_req_t); + + while (nl < end_cqr) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + nl +=16; + } + + nl = (char *) loop_cqr->cpaddr; + + if (loop_cqr->cplength > 40 ) { /* log only parts of the CP */ + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Start of channel program:\n"); + + for (i = 0; i < 20; i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "End of channel program:\n"); + + nl = (char *) loop_cqr->cpaddr; + nl += ((loop_cqr->cplength - 10) * 8); + + for (i = 0; i < 20; i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + + } else { /* log the whole CP */ + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Channel program (complete):\n"); + + for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + } + + /* log bytes arround failed CCW if not already done */ + begin = (char *) loop_cqr->cpaddr; + end = begin + ((loop_cqr->cplength+4) * 8); + nl = (void *)cpa; + + if (loop_cqr == cqr) { /* log only once */ + + if ((loop_cqr->cplength > 40) || /* not whole CP was logged or */ + ((nl < begin ) && /* CCW is outside logged CP */ + (nl > end ) ) ) { + + nl -= 10*8; /* start some bytes before */ + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Failed CCW (%p) (area):\n", + (void *)cpa); + + for (i = 0; i < 20; i += 2) { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); + + nl += 16; + } + + } else { + + len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER + "Failed CCW (%p) already logged\n", + (void *)cpa); + } + } + + printk ("%s", page); + loop_cqr = loop_cqr->refers; + } + + free_page ((unsigned long) page); + +} /* end log_erp_chain */ +#endif /* ERP_DEBUG */ + + +/* + ***************************************************************************** + * SECTION ERP EXAMINATION + ***************************************************************************** + */ /* * DASD_3990_ERP_EXAMINE_24 @@ -52,7 +202,7 @@ * * Each bit configuration leading to an action code 2 (Exit with * programming error or unusual condition indication) - * and 10 (disabled interface) are handled as fatal error´s. + * are handled as fatal error´s. * * All other configurations are handled as recoverable errors. * @@ -64,31 +214,58 @@ dasd_3990_erp_examine_24 (char *sense) { - /* check for 'Command Recejct' whithout environmental data present */ - if (sense[0] & 0x80) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } - } - - /* check for 'Invalid Track Format' whithout environmental data present */ - if (sense[1] & 0x40) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } + /* check for 'Command Recejct' which is always a fatal error */ + if (sense[0] & SNS0_CMD_REJECT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } + } + /* check for 'Invalid Track Format' */ + if (sense[1] & SNS1_INV_TRACK_FORMAT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } } /* check for 'No Record Found' */ - if (sense[1] & 0x08) { - return dasd_era_fatal; + if (sense[1] & SNS1_NO_REC_FOUND) { + return dasd_era_fatal; } /* return recoverable for all others */ return dasd_era_recover; -} /* END dasd_3990_erp_examine_24 */ +} /* END dasd_3990_erp_examine_24 */ + +/* + * DASD_3990_ERP_EXAMINE_32 + * + * DESCRIPTION + * Checks only for fatal/no/recoverable error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * RETURN VALUES + * dasd_era_none no error + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for recoverable others. + */ +dasd_era_t +dasd_3990_erp_examine_32 (char *sense) +{ + + switch (sense[25]) { + case 0x00: + return dasd_era_none; + case 0x01: + return dasd_era_fatal; + default: + return dasd_era_recover; + } + +} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE @@ -107,10 +284,12 @@ * dasd_era_recover for all others. */ dasd_era_t -dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat) +dasd_3990_erp_examine (ccw_req_t *cqr, + devstat_t *stat) { - char *sense = stat->ii.sense.data; + char *sense = stat->ii.sense.data; + dasd_era_t era = dasd_era_recover; /* check for successful execution first */ if (stat->cstat == 0x00 && @@ -118,19 +297,2821 @@ return dasd_era_none; /* distinguish between 24 and 32 byte sense data */ - if (sense[27] & 0x80) { + if (sense[27] & DASD_SENSE_BIT_0) { + + /* examine the 24 byte sense data */ + era = dasd_3990_erp_examine_24 (sense); + + } else { /* examine the 32 byte sense data */ - return dasd_3990_erp_examine_32 (sense); + era = dasd_3990_erp_examine_32 (sense); + + } /* end distinguish between 24 and 32 byte sense data */ + +#ifdef ERP_DEBUG + if (era == dasd_era_fatal) { + + log_erp_chain (cqr, + 0, + stat->cpa); + } +#endif /* ERP_DEBUG */ + + return era; + +} /* END dasd_3990_erp_examine */ + +/* + ***************************************************************************** + * SECTION ERP HANDLING + ***************************************************************************** + */ +/* + ***************************************************************************** + * 24 and 32 byte sense ERP functions + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_BLOCK_QUEUE + * + * DESCRIPTION + * Block the given device request queue to prevent from further + * processing until the started timer has expired or an related + * interrupt was received. + * + * PARAMETER + * erp request to be blocked + * expires time to wait until restart (in seconds) + * + * RETURN VALUES + * void + */ +void +dasd_3990_erp_block_queue (ccw_req_t *erp, + unsigned long expires) +{ + + dasd_device_t *device = erp->device; + + DASD_MESSAGE (KERN_INFO, device, + "blocking request queue for %is", + (int) expires); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_PENDING); + + /* restart queue after some time */ + device->timer.function = dasd_3990_erp_restart_queue; + device->timer.data = (unsigned long) erp; + device->timer.expires = jiffies + (expires * HZ); + add_timer(&device->timer); + +} /* end dasd_3990_erp_block_queue */ + +/* + * DASD_3990_ERP_RESTART_QUEUE + * + * DESCRIPTION + * Restarts request currently in status PENDING. + * This has to be done if either an related interrupt has received, or + * a timer has expired. + * + * + * PARAMETER + * erp pointer to the PENDING ERP + * + * RETURN VALUES + * void + * + */ +void +dasd_3990_erp_restart_queue (unsigned long erp) +{ + ccw_req_t *cqr = (void *) erp; + dasd_device_t *device = cqr->device; + unsigned long flags; + + /* get the needed locks to modify the request queue */ + s390irq_spin_lock_irqsave (device->devinfo.irq, + flags); + + /* 'restart' the device queue */ + if (cqr->status == CQR_STATUS_PENDING){ + + DASD_MESSAGE (KERN_INFO, device, + "%s", + "request queue restarted by MIH"); + + check_then_set (&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); + } + + /* release the lock */ + s390irq_spin_unlock_irqrestore (device->devinfo.irq, + flags); + + dasd_schedule_bh(device); + +} /* end dasd_3990_erp_restart_queue */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_INT_REQ + * + * DESCRIPTION + * Handles 'Intervention Required' error. + * This means either device offline or not installed. + * + * PARAMETER + * erp current erp + * RETURN VALUES + * erp modified erp + */ +ccw_req_t * +dasd_3990_erp_int_req (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + /* first time set initial retry counter and erp_function */ + if (erp->function != dasd_3990_erp_int_req) { + erp->retries = 256; + erp->function = dasd_3990_erp_int_req; + } + + /* issue a message and wait for 'device ready' interrupt */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "is offline or not installed - " + "INTERVENTION REQUIRED!!\n"); + + dasd_3990_erp_block_queue (erp, + 60); + + return erp; + +} /* end dasd_3990_erp_int_req */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ALTERNATE_PATH + * + * DESCRIPTION + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp modified pointer to the ERP + * + */ +void +dasd_3990_erp_alternate_path (ccw_req_t *erp) +{ + + dasd_device_t *device = erp->device; + int irq = device->devinfo.irq; + + /* dissable current channel path - this causes the use of an other + channel path if there is one.. */ + + DASD_MESSAGE (KERN_WARNING, device, + "disable lpu %x", + erp->dstat->lpum); + + /* try alternate valid path */ + erp->lpm &= ~(erp->dstat->lpum); + erp->options |= DOIO_VALID_LPM; /* use LPM for DO_IO */ + + if ((erp->lpm & ioinfo[irq]->opm) != 0x00) { + + DASD_MESSAGE (KERN_WARNING, device, + "try alternate lpm %x", + erp->lpm); + + /* reset status to queued to handle the request again... */ + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + erp->retries = 1; + } else { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "No alternate channel path left -> " + "permanent error"); + + /* post request with permanent error */ + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); - /* examine the 24 byte sense data */ - return dasd_3990_erp_examine_24 (sense); + } + +} /* end dasd_3990_erp_alternate_path */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_DCTL + * + * DESCRIPTION + * Setup cqr to do the Diagnostic Control (DCTL) command with an + * Inhibit Write subcommand (0x20) and the given modifier. + * + * PARAMETER + * erp pointer to the current ERP + * modifier subcommand modifier + * + * RETURN VALUES + * dctl_cqr pointer to NEW dctl_cqr + * + */ +ccw_req_t * +dasd_3990_erp_DCTL (ccw_req_t *erp, + char modifier) +{ + DCTL_data_t *DCTL_data; + ccw1_t *ccw; + ccw_req_t *dctl_cqr = dasd_alloc_request ((char *) &erp->magic, + 1, + sizeof(DCTL_data_t)); + + if (dctl_cqr == NULL) { + BUG(); + } + + DCTL_data = dctl_cqr->data; + + DCTL_data->subcommand = 0x02; /* Inhibit Write */ + DCTL_data->modifier = modifier; + + ccw = dctl_cqr->cpaddr; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = CCW_CMD_DCTL; + ccw->count = 4; + set_normalized_cda(ccw, __pa (DCTL_data)); + + dctl_cqr->function = dasd_3990_erp_DCTL; + dctl_cqr->refers = erp; + dctl_cqr->device = erp->device; + dctl_cqr->magic = erp->magic; + dctl_cqr->lpm = LPM_ANYPATH; + dctl_cqr->expires = 5 * TOD_MIN; + dctl_cqr->retries = 2; + asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk)); + + dctl_cqr->status = CQR_STATUS_FILLED; + + return dctl_cqr; + +} /* end dasd_3990_erp_DCTL */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ACTION_1 + * + * DESCRIPTION + * Setup ERP to do the ERP action 1 (see Reference manual). + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_1 (ccw_req_t *erp) +{ + erp->function = dasd_3990_erp_action_1; + + dasd_3990_erp_alternate_path (erp); + + return erp; + +} /* end dasd_3990_erp_action_1 */ + +/* + * DASD_3990_ERP_ACTION_4 + * + * DESCRIPTION + * Setup ERP to do the ERP action 4 (see Reference manual). + * Set the current request to PENDING to block the CQR queue for that device + * until the state change interrupt appears. + * Use a timer (20 seconds) to retry the cqr if the interrupt is still missing. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_4 (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + /* first time set initial retry counter and erp_function */ + /* and retry once without waiting for state change pending */ + /* interrupt (this enables easier enqueing of the cqr) */ + if (erp->function != dasd_3990_erp_action_4) { + erp->retries = 255; + erp->function = dasd_3990_erp_action_4; + + } else { + + if (sense[25] & 0x1D) { /* state change pending */ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "waiting for state change pending " + "int"); + + dasd_3990_erp_block_queue (erp, + 30); + + } else { + /* no state change pending - retry */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "no state change pending - retry"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } + + return erp; + +} /* end dasd_3990_erp_action_4 */ + +/* + ***************************************************************************** + * 24 byte sense ERP functions (only) + ***************************************************************************** + */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_ACTION_5 + * + * DESCRIPTION + * Setup ERP to do the ERP action 5 (see Reference manual). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_5 (ccw_req_t *erp) +{ + /* first of all retry */ + erp->retries = 10; + erp->function = dasd_3990_erp_action_5; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + /* further handling is done in xxx_further_erp after the retries */ + + return erp; + +} /* end dasd_3990_erp_action_5 */ + +/* + * DASD_3990_HANDLE_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Enviromental data present'. + * Does a analysis of the sense data (message Format) + * and prints the error messages. + * + * PARAMETER + * sense current sense data + * + * RETURN VALUES + * void + */ +void +dasd_3990_handle_env_data (char *sense) +{ + /* check bytes 7-23 for further information */ + + char msg_format = (sense[7] & 0xF0); + char msg_no = (sense[7] & 0x0F); + + switch (msg_format) { + case 0x00: /* Format 0 - Program or System Checks */ + + if (sense[1] & 0x10) { /* check message to operator bit */ + + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Command\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Command Sequence\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - CCW Count less than " + "required\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Parameter\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Diagnostic of Sepecial " + "Command Violates File Mask\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Channel Returned with " + "Incorrect retry CCW\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reset Notification\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Storage Path Restart\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Channel requested ... %02x\n", + sense[8]); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Invalid Defective/Alternate " + "Track Pointer\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - DPS Installation Check\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Command Invalid on Secondary " + "Address\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Status Not As Required: " + "reason %02x\n", + sense[8]); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reseved\n"); + } + } else { + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Device Error Source\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reserved\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Device Fenced - device = " + "%02x\n", + sense[4]); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Data Pinned for Device\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 0 - Reserved\n"); + } + } + break; + + case 0x10: /* Format 1 - Device Equipment Checks */ + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device Status 1 not as " + "expected\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Index missing\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Interruption cannot be reset\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device did not respond to " + "selection\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device check-2 error or Set " + "Sector is not complete\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Head address does not compare\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device status 1 not valid\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Device not ready\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Track physical address did " + "not compare\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Missing device address bit\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Drive motor switch is off\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Seek incomplete\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Cylinder address did not " + "compare\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Offset active cannot be reset\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 1 - Reserved\n"); + } + break; + + case 0x20: /* Format 2 - 3990 Equipment Checks */ + switch (msg_no) { + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - 3990 check-2 error\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - Support facility errors\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - Microcode detected error %02x\n", + sense[8]); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 2 - Reserved\n"); + } + break; + + case 0x30: /* Format 3 - 3990 Control Checks */ + switch (msg_no) { + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 3 - Allegiance terminated\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 3 - Reserved\n"); + } + break; + + case 0x40: /* Format 4 - Data Checks */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Home address area error\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Count area error\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Key area error\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Data area error\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in home address area\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in count address area\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in key area\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in data area\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Home address area error; " + "offset active\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Count area error; offset active\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Key area error; offset active\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Data area error; offset active\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in home address area; " + "offset active\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in count address area; " + "offset active\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No sync byte in key area; " + "offset active\n"); + break; + case 0x0F: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - No syn byte in data area; " + "offset active\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 4 - Reserved\n"); + } + break; + + case 0x50: /* Format 5 - Data Check with displacement information */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the home address area\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the count area\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the key area\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the data area\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the home address area; " + "offset active\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the count area; " + "offset active\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the key area; " + "offset active\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Data Check in the data area; " + "offset active\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 5 - Reserved\n"); + } + break; + + case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel A\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel B\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel C\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel D\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel E\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel F\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel G\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Overrun on channel H\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 6 - Reserved\n"); + } + break; + + case 0x70: /* Format 7 - Device Connection Control Checks */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - RCC initiated by a connection " + "check alert\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - RCC 1 sequence not successful\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - RCC 1 and RCC 2 sequences not " + "successful\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid tag-in during selection " + "sequence\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - extra RCC required\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid DCC selection response " + "or timeout\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Missing end operation; device " + "transfer complete\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Missing end operation; device " + "transfer incomplete\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid tag-in for an immediate " + "command sequence\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Invalid tag-in for an extended " + "command sequence\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - 3990 microcode time out when " + "stopping selection\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - No response to selection after " + "a poll interruption\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Permanent path error (DASD " + "controller not available)\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - DASD controller not available on " + "disconnected command chain\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 7 - Reserved\n"); + } + break; + + case 0x80: /* Format 8 - Additional Device Equipment Checks */ + switch (msg_no) { + case 0x00: /* No Message */ + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Error correction code hardware " + "fault\n"); + break; + case 0x03: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Unexpected end operation response " + "code\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - End operation with transfer count " + "not zero\n"); + break; + case 0x05: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - End operation with transfer " + "count zero\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - DPS checks after a system reset or " + "selective reset\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - DPS cannot be filled\n"); + break; + case 0x08: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Short busy time-out during device " + "selection\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - DASD controller failed to set or " + "reset the long busy latch\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - No interruption from device during " + "a command chain\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 8 - Reserved\n"); + } + break; + + case 0x90: /* Format 9 - Device Read, Write, and Seek Checks */ + switch (msg_no) { + case 0x00: + break; /* No Message */ + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Device check-2 error\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Head address did not compare\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Track physical address did not " + "compare while oriented\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Cylinder address did not compare\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT 9 - Reserved\n"); + } + break; + + case 0xF0: /* Format F - Cache Storage Checks */ + switch (msg_no) { + case 0x00: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Operation Terminated\n"); + break; + case 0x01: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Subsystem Processing Error\n"); + break; + case 0x02: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Cache or nonvolatile storage " + "equipment failure\n"); + break; + case 0x04: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Caching terminated\n"); + break; + case 0x06: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Cache fast write access not " + "authorized\n"); + break; + case 0x07: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Track format incorrect\n"); + break; + case 0x09: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Caching reinitiated\n"); + break; + case 0x0A: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Nonvolatile storage terminated\n"); + break; + case 0x0B: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Volume is suspended duplex\n"); + break; + case 0x0C: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Subsystem status connot be " + "determined\n"); + break; + case 0x0D: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - Caching status reset to default\n"); + break; + case 0x0E: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT F - DASD Fast Write inhibited\n"); + break; + default: + printk (KERN_WARNING PRINTK_HEADER + "FORMAT D - Reserved\n"); + } + break; + + default: /* unknown message format - should not happen */ + + } /* end switch message format */ + +} /* end dasd_3990_handle_env_data */ + +/* + * DASD_3990_ERP_COM_REJ + * + * DESCRIPTION + * Handles 24 byte 'Command Reject' error. + * + * PARAMETER + * erp current erp_head + * sense current sense data + * + * RETURN VALUES + * erp 'new' erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_com_rej (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + ccw_req_t *cqr = NULL; + + erp->function = dasd_3990_erp_com_rej; + + /* env data present (ACTION 10 - retry should work) */ + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Command Reject - environmental data present\n"); + + dasd_3990_handle_env_data (sense); + + erp->retries = 5; + + } else { + /* fatal error - set status to FAILED */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Command Reject - Fatal error\n"); + + cqr = erp->refers; + + dasd_free_request (erp); + + erp = cqr; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + } + + return erp; + +} /* end dasd_3990_erp_com_rej */ + +/* + * DASD_3990_ERP_BUS_OUT + * + * DESCRIPTION + * Handles 24 byte 'Bus Out Parity Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_bus_out (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + + /* first time set initial retry counter and erp_function */ + if (erp->function != dasd_3990_erp_bus_out) { + erp->retries = 256; + erp->function = dasd_3990_erp_bus_out; + } + + /* issue a message and wait for 'device ready' interrupt */ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "bus out parity error or BOPC requested by channel\n"); + + dasd_3990_erp_block_queue (erp, + 60); + + return erp; + +} /* end dasd_3990_erp_bus_out */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_EQUIP_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Equipment Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_equip_check (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_equip_check; + +#ifdef ERP_FULL_ERP + if (sense[1] & SNS1_WRITE_INHIBITED) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write inhibited path encountered"); + + /* vary path offline */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Path should be varied off-line. " + "This is not implemented yet \n - please report to " + "linux390@de.ibm.com"); + + erp = dasd_3990_erp_action_1 (erp); + + } else +#endif /* ERP_FULL_ERP */ + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment Check - " + "environmental data present"); +#ifdef ERP_FULL_ERP + dasd_3990_handle_env_data (sense); +#endif /* ERP_FULL_ERP */ + + erp = dasd_3990_erp_action_4 (erp, + sense); + +#ifdef ERP_FULL_ERP + } else if (sense[1] & SNS1_PERM_ERR) { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment Check - retry exhausted or " + "undesirable\n"); + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* all other equipment checks - Action 5 */ + /* rest is done when retries == 0 */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment check or processing error\n"); + + erp = dasd_3990_erp_action_5 (erp); +#endif /* ERP_FULL_ERP */ + } + + return erp; + +} /* end dasd_3990_erp_equip_check */ + +/* + * DASD_3990_ERP_DATA_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Data Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_data_check (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_data_check; + +#ifdef ERP_FULL_ERP + if (sense[2] & SNS2_CORRECTABLE) { /* correctable data check */ + + /* issue message that the data has been corrected */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Data recovered during retry with PCI " + "fetch mode active\n"); + + /* not possible to handle this situation in Linux */ + panic("No way to inform appliction about the possibly " + "incorret data"); + + } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check recovered secondary " + "addr of duplex pair"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + } else if (sense[1] & SNS1_PERM_ERR) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check with internal " + "retry exhausted\n"); + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* all other data checks */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check with retry count " + "exhausted...\n"); + + erp = dasd_3990_erp_action_5 (erp); + } + +#else + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check recovered secondary " + "addr of duplex pair"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + + return erp; + +} /* end dasd_3990_erp_data_check */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_OVERRUN + * + * DESCRIPTION + * Handles 24 byte 'Overrun' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_overrun (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_overrun; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Overrun - service overrun or overrun" + " error requested by channel\n"); + + erp = dasd_3990_erp_action_5 (erp); + + return erp; + +} /* end dasd_3990_erp_overrun */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_INV_FORMAT + * + * DESCRIPTION + * Handles 24 byte 'Invalid Track Format' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_inv_format (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inv_format; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Track format error when destaging or " + "staging data"); + +#ifdef ERP_FULL_ERP + dasd_3990_handle_env_data (sense); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + } else { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Invalid Track Format - Fatal error should have " + "been handled within the interrupt handler\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } +#else + erp = dasd_3990_erp_action_4 (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + + return erp; + +} /* end dasd_3990_erp_inv_format */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_EOC + * + * DESCRIPTION + * Handles 24 byte 'End-of-Cylinder' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_EOC (ccw_req_t *erp, + char *sense) +{ + + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_EOC; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "End-of-Cylinder - must never happen\n"); + + /* implement action 7 */ + BUG(); + + return erp; + +} /* end dasd_3990_erp_EOC */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Environmental-Data Present' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_env_data (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_env_data; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Environmental data present"); +#ifdef ERP_FULL_ERP + dasd_3990_handle_env_data (sense); +#endif /* ERP_FULL_ERP */ + + erp = dasd_3990_erp_action_4 (erp, + sense); + + return erp; + +} /* end dasd_3990_erp_env_data */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_NO_REC + * + * DESCRIPTION + * Handles 24 byte 'No Record Found' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_no_rec (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_no_rec; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "No Record Found - Fatal error should " + "have been handled within the interrupt handler\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return erp; + +} /* end dasd_3990_erp_no_rec */ + +/* + * DASD_3990_ERP_FILE_PROT + * + * DESCRIPTION + * Handles 24 byte 'File Protected' error. + * Note: Seek related recovery is not implemented because + * wee don't use the seek command yet. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_file_prot (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_file_prot; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "File Protected\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return erp; + +} /* end dasd_3990_erp_file_prot */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_INSPECT_24 + * + * DESCRIPTION + * Does a detailed inspection of the 24 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp pointer to the (addtitional) ERP + */ +ccw_req_t * +dasd_3990_erp_inspect_24 ( ccw_req_t *erp, + char *sense) +{ + ccw_req_t *erp_filled = NULL; + dasd_device_t *device = erp->device; + + /* Check sense for .... */ +#ifdef ERP_FULL_ERP + /* 'Command Reject' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_CMD_REJECT)) { + erp_filled = dasd_3990_erp_com_rej (erp, + sense); + } + /* 'Intervention Required' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_INTERVENTION_REQ)) { + erp_filled = dasd_3990_erp_int_req (erp); + } + /* 'Bus Out Parity Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_BUS_OUT_CHECK)) { + erp_filled = dasd_3990_erp_bus_out (erp); + } +#endif /* ERP_FULL_ERP */ + /* 'Equipment Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_EQUIPMENT_CHECK)) { + erp_filled = dasd_3990_erp_equip_check (erp, + sense); + } + /* 'Data Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_DATA_CHECK)) { + erp_filled = dasd_3990_erp_data_check (erp, + sense); + } +#ifdef ERP_FULL_ERP + /* 'Overrun' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_OVERRUN)) { + erp_filled = dasd_3990_erp_overrun (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + /* 'Invalid Track Format' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_INV_TRACK_FORMAT)) { + erp_filled = dasd_3990_erp_inv_format (erp, + sense); + } +#ifdef ERP_FULL_ERP + /* 'End-of-Cylinder' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_EOC)) { + erp_filled = dasd_3990_erp_EOC (erp, + sense); + } +#endif /* ERP_FULL_ERP */ + /* 'Environmental Data' */ + if ((erp_filled == NULL) && + (sense[2] & SNS2_ENV_DATA_PRESENT)) { + erp_filled = dasd_3990_erp_env_data (erp, + sense); + } +#ifdef ERP_FULL_ERP + /* 'No Record Found' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_NO_REC_FOUND)) { + erp_filled = dasd_3990_erp_no_rec (erp, + sense); + } + /* 'File Protected' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_FILE_PROTECTED)) { + erp_filled = dasd_3990_erp_file_prot (erp); + } +#endif /* ERP_FULL_ERP */ + + /* other (unknown) error - do default ERP */ + if (erp_filled == NULL) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "default ERP taken"); + + erp_filled = erp; + } + + return erp_filled; + +} /* END dasd_3990_erp_inspect_24 */ + +/* + ***************************************************************************** + * 32 byte sense ERP functions (only) + ***************************************************************************** + */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERPACTION_10_32 + * + * DESCRIPTION + * Handles 32 byte 'Action 10' of Single Program Action Codes. + * Just retry and if retry doesn't work, return with error. + * + * PARAMETER + * erp current erp_head + * sense current sense data + * RETURN VALUES + * erp modified erp_head + */ +ccw_req_t * +dasd_3990_erp_action_10_32 (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->retries = 256; + erp->function = dasd_3990_erp_action_10_32; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Perform logging requested\n"); + + return erp; + +} /* end dasd_3990_erp_action_10_32 */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_ACTION_1B_32 + * + * DESCRIPTION + * Handles 32 byte 'Action 1B' of Single Program Action Codes. + * A write operation could not be finished because of an unexpected + * condition. + * The already created 'default erp' is used to get the link to + * the erp chain, but it can not be used for this recovery + * action because it contains no DE/LO data space. + * + * PARAMETER + * default_erp already created default erp. + * sense current sense data + * RETURN VALUES + * erp new erp or + * default_erp in case of imprecise ending or error + */ +ccw_req_t * +dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, + char *sense) +{ + dasd_device_t *device = default_erp->device; + __u32 cpa = 0; + ccw_req_t *cqr; + ccw_req_t *erp; + DE_eckd_data_t *DE_data; + char *LO_data; /* LO_eckd_data_t */ + ccw1_t *ccw; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write not finsihed because of unexpected condition"); + + default_erp->function = dasd_3990_erp_action_1B_32; + + /* determine the original cqr */ + cqr = default_erp; + while (cqr->refers != NULL){ + cqr = cqr->refers; + } + + /* for imprecise ending just do default erp */ + if (sense[1] & 0x01) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Imprecise ending is set - just retry"); + + return default_erp; + } + + /* determine the address of the CCW to be restarted */ + /* Imprecise ending is not set -> addr from IRB-SCSW */ + cpa = default_erp->refers->dstat->cpa; + + if (cpa == 0) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to determine address of the CCW " + "to be restarted"); + + check_then_set (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* Build new ERP request including DE/LO */ + erp = dasd_alloc_request ((char *) &cqr->magic, + 2 + 1, /* DE/LO + TIC */ + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + + if ( !erp ) { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to allocate ERP"); + + check_then_set (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* use original DE */ + DE_data = erp->data; + memcpy (DE_data, + cqr->data, + sizeof (DE_eckd_data_t)); + + /* create LO */ + LO_data = erp->data + sizeof (DE_eckd_data_t); + + if ((sense[3] == 0x01) && + (LO_data[1] & 0x01) ){ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "BUG - this should not happen"); + //BUG(); /* check for read count suffixing n.a. */ + } + + if ((sense[7] & 0x3F) == 0x01) { + /* operation code is WRITE DATA -> data area orientation */ + LO_data[0] = 0x81; + + } else if ((sense[7] & 0x3F) == 0x03) { + /* operation code is FORMAT WRITE -> index orientation */ + LO_data[0] = 0xC3; + + } else { + LO_data[0] = sense[7]; /* operation */ + } + + LO_data[1] = sense[8]; /* auxiliary */ + LO_data[2] = sense[9]; + LO_data[3] = sense[3]; /* count */ + LO_data[4] = sense[29]; /* seek_addr.cyl */ + LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ + LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ + + memcpy (&(LO_data[8]), &(sense[11]), 8); + + /* create DE ccw */ + ccw = erp->cpaddr; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + set_normalized_cda (ccw, __pa (DE_data)); + + /* create LO ccw */ + ccw++; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + set_normalized_cda (ccw, __pa (LO_data)); + + /* TIC to the failed ccw */ + ccw++; + ccw->cmd_code = CCW_CMD_TIC; + ccw->cda = cpa; + + /* fill erp related fields */ + erp->function = dasd_3990_erp_action_1B_32; + erp->refers = default_erp->refers; + erp->device = device; + erp->magic = default_erp->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 255; + erp->status = CQR_STATUS_FILLED; + + /* remove the default erp */ + dasd_free_request (default_erp); + + return erp; + +} /* end dasd_3990_erp_action_1B_32 */ + +/* + * DASD_3990_UPDATE_1B + * + * DESCRIPTION + * Handles the update to the 32 byte 'Action 1B' of Single Program + * Action Codes in case the first action was not successful. + * The already created 'previous_erp' is the currently not successful + * ERP. + * + * PARAMETER + * previous_erp already created previous erp. + * sense current sense data + * RETURN VALUES + * erp modified erp + */ +ccw_req_t * +dasd_3990_update_1B (ccw_req_t *previous_erp, + char *sense) +{ + dasd_device_t *device = previous_erp->device; + __u32 cpa = 0; + ccw_req_t *cqr; + ccw_req_t *erp; + char *LO_data; /* LO_eckd_data_t */ + ccw1_t *ccw; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write not finsihed because of unexpected condition" + " - follow on"); + + /* determine the original cqr */ + cqr = previous_erp; + while (cqr->refers != NULL){ + cqr = cqr->refers; + } + + /* for imprecise ending just do default erp */ + if (sense[1] & 0x01) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Imprecise ending is set - just retry"); + + check_then_set (&previous_erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + return previous_erp; + } + + /* determine the address of the CCW to be restarted */ + /* Imprecise ending is not set -> addr from IRB-SCSW */ + cpa = previous_erp->dstat->cpa; + + if (cpa == 0) { + ccw = cqr->cpaddr; /* addr of first data transfer */ + ccw++; /* command in domain */ + ccw++; + cpa = (__u32) ccw; + } + + if (cpa == 0) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to determine address of the CCW " + "to be restarted"); + + check_then_set (&previous_erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return previous_erp; + } + + erp = previous_erp; + + /* update the LO with the new returned sense data */ + LO_data = erp->data + sizeof (DE_eckd_data_t); + + if ((sense[3] == 0x01) && + (LO_data[1] & 0x01) ){ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "BUG - this should not happen"); + //BUG(); /* check for read count suffixing n.a. */ + } + + if ((sense[7] & 0x3F) == 0x01) { + /* operation code is WRITE DATA -> data area orientation */ + LO_data[0] = 0x81; + + } else if ((sense[7] & 0x3F) == 0x03) { + /* operation code is FORMAT WRITE -> index orientation */ + LO_data[0] = 0xC3; + + } else { + LO_data[0] = sense[7]; /* operation */ + } + + LO_data[1] = sense[8]; /* auxiliary */ + LO_data[2] = sense[9]; + LO_data[3] = sense[3]; /* count */ + LO_data[4] = sense[29]; /* seek_addr.cyl */ + LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ + LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ + + memcpy (&(LO_data[8]), &(sense[11]), 8); + + /* TIC to the failed ccw */ + ccw = erp->cpaddr; /* addr of DE ccw */ + ccw++; /* addr of LE ccw */ + ccw++; /* addr of TIC ccw */ + ccw->cda = cpa; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + return erp; + +} /* end dasd_3990_update_1B */ + +#ifdef ERP_FULL_ERP +/* + * DASD_3990_ERP_COMPOUND_RETRY + * + * DESCRIPTION + * Handles the compound ERP action retry code. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp modified ERP pointer + * + */ +void +dasd_3990_erp_compound_retry (ccw_req_t *erp, + char *sense) +{ + switch (sense[25] & 0x03) { + case 0x00: /* no not retry */ + erp->retries = 0; + break; + + case 0x01: /* retry 2 times */ + erp->retries = 2; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + break; + + case 0x02: /* retry 10 times */ + erp->retries = 10; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + break; + + case 0x03: /* retry 255 times */ + erp->retries = 255; + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + break; + + default: + BUG(); + } + + erp->function = dasd_3990_erp_compound_retry; + +} /* end dasd_3990_erp_compound_retry */ + +/* + * DASD_3990_ERP_COMPOUND_PATH + * + * DESCRIPTION + * Handles the compound ERP action for retry on alternate + * channel path. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp modified ERP pointer + * + */ +void +dasd_3990_erp_compound_path (ccw_req_t *erp, + char *sense) +{ + + if (sense[25] & DASD_SENSE_BIT_3) { + dasd_3990_erp_alternate_path (erp); + + if (erp->status == CQR_STATUS_FAILED) { + /* reset the lpm and the status to be able to + * try further actions. */ + + erp->lpm = LPM_ANYPATH; + + check_then_set (&erp->status, + CQR_STATUS_FAILED, + CQR_STATUS_ERROR); + + } + } + + erp->function = dasd_3990_erp_compound_path; + +} /* end dasd_3990_erp_compound_path */ + +/* + * DASD_3990_ERP_COMPOUND_CODE + * + * DESCRIPTION + * Handles the compound ERP action for retry code. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp NEW ERP pointer + * + */ +ccw_req_t * +dasd_3990_erp_compound_code (ccw_req_t *erp, + char *sense) +{ + + + if (sense[25] & DASD_SENSE_BIT_2) { + + switch (sense[28]) { + case 0x17: + /* issue a Diagnostic Control command with an + * Inhibit Write subcommand and controler modifier */ + erp = dasd_3990_erp_DCTL (erp, + 0x20); + break; + + case 0x25: + /* wait for 5 seconds and retry again */ + erp->retries = 1; + + dasd_3990_erp_block_queue (erp, + 5); + break; + + default: + BUG(); + } + } + + erp->function = dasd_3990_erp_compound_code; + + return erp; + +} /* end dasd_3990_erp_compound_code */ + +/* + * DASD_3990_ERP_COMPOUND_CONFIG + * + * DESCRIPTION + * Handles the compound ERP action for configruation + * dependent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp modified ERP pointer + * + */ +void +dasd_3990_erp_compound_config (ccw_req_t *erp, + char *sense) +{ + if ((sense[25] & DASD_SENSE_BIT_1) && + (sense[26] & DASD_SENSE_BIT_2) ) { + + /* set to suspended duplex state then restart */ + dasd_device_t *device = erp->device; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Set device to suspended duplex state should be done!\n" + "This is not implemented yet (for compound ERP)\n" + " - please report to linux390@de.ibm.com"); + + } + + erp->function = dasd_3990_erp_compound_config; + +} /* end dasd_3990_erp_compound_config */ + +/* + * DASD_3990_ERP_COMPOUND + * + * DESCRIPTION + * Does a detailed inspection of the 32 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created ERP + * + * RETURN VALUES + * erp (additional) ERP pointer + * + */ +ccw_req_t * +dasd_3990_erp_compound (ccw_req_t *erp, + char *sense) +{ + if ((erp->function != dasd_3990_erp_compound_retry ) && + (erp->function != dasd_3990_erp_compound_path ) && + (erp->function != dasd_3990_erp_compound_code ) && + (erp->function != dasd_3990_erp_compound_config) ) { + + /* called first time */ + dasd_3990_erp_compound_retry (erp, + sense); + } + + /* do further action if no retry is specified / left */ + if ((erp->function == dasd_3990_erp_compound_retry) && + (erp->status == CQR_STATUS_ERROR ) ){ + + dasd_3990_erp_compound_path (erp, + sense); + } + + if ((erp->function == dasd_3990_erp_compound_path) && + (erp->status == CQR_STATUS_ERROR ) ){ + + erp = dasd_3990_erp_compound_code (erp, + sense); + } + + if ((erp->function == dasd_3990_erp_compound_code) && + (erp->status == CQR_STATUS_ERROR ) ){ + + dasd_3990_erp_compound_config (erp, + sense); + } + + /* if no compound action ERP specified, the request failed */ + if (erp->status == CQR_STATUS_ERROR) { + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + + return erp; + +} /* end dasd_3990_erp_compound */ +#endif /* ERP_FULL_ERP */ + +/* + * DASD_3990_ERP_INSPECT_32 + * + * DESCRIPTION + * Does a detailed inspection of the 32 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp_filled pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_inspect_32 ( ccw_req_t *erp, + char *sense ) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inspect_32; + + if (sense[25] & DASD_SENSE_BIT_0) { + + /* compound program action codes (byte25 bit 0 == '1') */ +#ifdef ERP_FULL_ERP + erp = dasd_3990_erp_compound (erp, + sense); +#else + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "default ERP taken"); +#endif /* ERP_FULL_ERP */ + + } else { + + /* single program action codes (byte25 bit 0 == '0') */ + switch (sense[25]) { +#ifdef ERP_FULL_ERP + case 0x00: /* success */ + DASD_MESSAGE (KERN_WARNING, device, + "ERP called for successful request %p" + " - NO ERP necessary", + erp); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + break; + + case 0x01: /* fatal error */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Fatal error should " + "have been handled within the interrupt handler\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + break; + + case 0x02: /* intervention required */ + case 0x03: /* intervention required during dual copy */ + erp = dasd_3990_erp_int_req (erp); + break; + + case 0x0F: /* length mismatch during update write command */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "update write command error - should not happen; " + "Please send this message together with the above " + "sense data to linux390@de.ibm.com\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + break; + + case 0x10: /* logging required for other channel program */ + erp = dasd_3990_erp_action_10_32 (erp, + sense); + break; + + case 0x15: /* next track outside defined extend */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "next track outside defined extend - should not happen; " + "Please send this message together with the above " + "sense data to linux390@de.ibm.com\n"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + break; +#endif /* ERP_FULL_ERP */ + + case 0x1B: /* unexpected condition during write */ + + erp = dasd_3990_erp_action_1B_32 (erp, + sense); + break; + +#ifdef ERP_FULL_ERP + case 0x1C: /* invalid data */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Data recovered during retry with PCI " + "fetch mode active\n"); + + /* not possible to handle this situation in Linux */ + panic("No way to inform appliction about the possibly " + "incorret data"); + break; +#endif /* ERP_FULL_ERP */ + + case 0x1D: /* state-change pending */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "A State change pending condition exists " + "for the subsystem or device"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + break; + + default: /* all others errors */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "default ERP taken"); + } + } + + return erp; + +} /* end dasd_3990_erp_inspect_32 */ + +/* + ***************************************************************************** + * main ERP control fuctions (24 and 32 byte sense) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_INSPECT + * + * DESCRIPTION + * Does a detailed inspection for sense data by calling either + * the 24-byte or the 32-byte inspection routine. + * + * PARAMETER + * erp pointer to the currently created default ERP + * RETURN VALUES + * erp_new contens was possibly modified + */ +ccw_req_t * +dasd_3990_erp_inspect (ccw_req_t *erp) +{ + ccw_req_t *erp_new = NULL; + /* sense data are located in the refers record of the */ + /* already set up new ERP ! */ + char *sense = erp->refers->dstat->ii.sense.data; + + /* distinguish between 24 and 32 byte sense data */ + if (sense[27] & DASD_SENSE_BIT_0) { + + /* inspect the 24 byte sense data */ + erp_new = dasd_3990_erp_inspect_24 (erp, + sense); + + } else { + + /* inspect the 32 byte sense data */ + erp_new = dasd_3990_erp_inspect_32 (erp, + sense); + + } /* end distinguish between 24 and 32 byte sense data */ + + return erp_new; + +} /* END dasd_3990_erp_inspect */ + +/* + * DASD_3990_ERP_ADD_ERP + * + * DESCRIPTION + * This funtion adds an additional request block (ERP) to the head of + * the given cqr (or erp). + * This erp is initialized as an default erp (retry TIC) + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_add_erp (ccw_req_t *cqr) +{ + /* allocate additional request block */ + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); + if ( !erp ) { + printk( KERN_WARNING PRINTK_HEADER + "unable to allocate ERP request\n" ); + return NULL; + } + + /* initialize request with default TIC to current ERP/CQR */ + erp->cpaddr->cmd_code = CCW_CMD_TIC; + erp->cpaddr->cda = ((__u32) cqr->cpaddr); + erp->function = dasd_3990_erp_add_erp; + erp->refers = cqr; + erp->device = cqr->device; + erp->magic = cqr->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 255; + + erp->status = CQR_STATUS_FILLED; + + return erp; +} + +/* + * DASD_3990_ERP_ADDITIONAL_ERP + * + * DESCRIPTION + * An additional ERP is needed to handle the current error. + * Add ERP to the head of the ERP-chain containing the ERP processing + * determined based on the sense data. + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_additional_erp (ccw_req_t *cqr) +{ + + ccw_req_t *erp = NULL; + + /* add erp and initialize with default TIC */ + erp = dasd_3990_erp_add_erp (cqr); + + /* inspect sense, determine specific ERP if possible */ + if (erp != NULL) { + erp = dasd_3990_erp_inspect (erp); + } + + return erp; + +} /* end dasd_3990_erp_additional_erp */ + +/* + * DASD_3990_ERP_ERROR_MATCH + * + * DESCRIPTION + * check if the the device status of the given cqr is the same. + * This means that the failed CCW and the relevant sense data + * must match. + * I don't distinguish between 24 and 32 byte sense becaus in case of + * 24 byte sense byte 25 and 27 is set as well. + * + * PARAMETER + * cqr1 first cqr, which will be compared with the + * cqr2 second cqr. + * + * RETURN VALUES + * match 'boolean' for match found + * returns 1 if match found, otherwise 0. + */ +int +dasd_3990_erp_error_match (ccw_req_t *cqr1, + ccw_req_t *cqr2) +{ + /* check failed CCW */ + if (cqr1->dstat->cpa != + cqr2->dstat->cpa) { + // return 0; /* CCW doesn't match */ + printk(KERN_WARNING PRINTK_HEADER + "_error_match: CCW doesn't match -> ignore\n"); + } + /* check sense data; byte 0-2,25,27 */ + if (!((strncmp (cqr1->dstat->ii.sense.data, + cqr2->dstat->ii.sense.data, + 3) == 0) && + (cqr1->dstat->ii.sense.data[27] == + cqr2->dstat->ii.sense.data[27] ) && + (cqr1->dstat->ii.sense.data[25] == + cqr2->dstat->ii.sense.data[25] ) )) { + + return 0; /* sense doesn't match */ + } + return 1; /* match */ + +} /* end dasd_3990_erp_error_match */ + +/* + * DASD_3990_ERP_IN_ERP + * + * DESCRIPTION + * check if the current error already happened before. + * quick exit if current cqr is not an ERP (cqr->refers=NULL) + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the already defined error recovery procedure OR + * NULL if a 'new' error occurred. + */ +ccw_req_t * +dasd_3990_erp_in_erp (ccw_req_t *cqr) +{ + ccw_req_t *erp_head = cqr, /* save erp chain head */ + *erp_match = NULL; /* save erp chain head */ + int match = 0; /* 'boolean' for matching error found */ + + if (cqr->refers == NULL) { /* return if not in erp */ + return NULL; + } + /* check the erp/cqr chain for current error */ + do { + match = dasd_3990_erp_error_match (erp_head, + cqr->refers); + erp_match = cqr; /* save possible matching erp */ + cqr = cqr->refers; /* check next erp/cqr in queue */ + } while ((cqr->refers != NULL) && + (match == 0)); + + if (match) { + return erp_match; /* return address of matching erp */ + } else { + return NULL; /* return NULL to indicate that no match + was found */ + } + +} /* END dasd_3990_erp_in_erp */ + +/* + * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense) + * + * DESCRIPTION + * No retry is left for the current ERP. Check what has to be done + * with the ERP. + * - do further defined ERP action or + * - wait for interrupt or + * - exit with permanent error + * + * PARAMETER + * erp ERP which is in progress wiht no retry left + * + * RETURN VALUES + * erp modified/additional ERP + */ +ccw_req_t * +dasd_3990_erp_further_erp (ccw_req_t *erp) +{ + dasd_device_t *device = erp->device; + +#ifdef ERP_FULL_ERP + /* check for 24 byte sense ERP */ + if ((erp->function == dasd_3990_erp_bus_out ) || + (erp->function == dasd_3990_erp_action_1) || + (erp->function == dasd_3990_erp_action_4) ){ + + erp = dasd_3990_erp_action_1 (erp); + + } else if (erp->function == dasd_3990_erp_action_5) { + + /* retries have not been successful */ + char *sense = erp->dstat->ii.sense.data; + + /* prepare erp for retry on different channel path */ + erp = dasd_3990_erp_action_1 (erp); + + if (!(sense[ 2] & DASD_SENSE_BIT_0)) { + + /* issue a Diagnostic Control command with an + * Inhibit Write subcommand */ + + switch (sense[25]) { + case 0x17: + case 0x57: { /* controller */ + erp = dasd_3990_erp_DCTL (erp, + 0x20); + break; + } + case 0x18: + case 0x58: { /* channel path */ + erp = dasd_3990_erp_DCTL (erp, + 0x40); + break; + } + case 0x19: + case 0x59: { /* storage director */ + erp = dasd_3990_erp_DCTL (erp, + 0x80); + break; + } + default: + DASD_MESSAGE (KERN_WARNING, device, + "invalid subcommand modifier 0x%x for " + "Diagnostic Control Command", + sense[25]); + } + } + +// /* check for 32 byte sense ERP */ +// } else if ((erp->function == dasd_3990_erp_xxx){ +#else + /* check for 24 byte sense ERP */ + if ((erp->function == dasd_3990_erp_action_1) || + (erp->function == dasd_3990_erp_action_4) ){ + + erp = dasd_3990_erp_action_1 (erp); +#endif /* ERP_FULL_ERP */ + + } else { + /* no retry left and no additional special handling necessary */ + DASD_MESSAGE (KERN_WARNING, device, + "no retries left for erp %p - " + "set status to FAILED", + erp); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + + return erp; + +} /* end dasd_3990_erp_further_erp */ + +/* + * DASD_3990_ERP_HANDLE_MATCH_ERP + * + * DESCRIPTION + * An error occurred again and an ERP has been detected which is already + * used to handle this error (e.g. retries). + * All prior ERP's are set to status DONE and the retry counter is + * decremented. + * If retry counter is already 0, it has to checked if further action + * is needed (besides retry) or if the ERP has failed. + * + * PARAMETER + * erp_head first ERP in ERP-chain + * erp_match ERP that handles the actual error. + * + * RETURN VALUES + * none + */ +void +dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head, + ccw_req_t *erp_match) +{ + + dasd_device_t *device = erp_head->device; + ccw_req_t *erp_done = erp_head; + ccw_req_t *erp_free = NULL; /* req to be freed */ + + /* loop over successful ERPs and remove them from chanq */ + while ((erp_done != erp_match) && + (erp_done != NULL)) { + +#ifdef ERP_DEBUG + DASD_MESSAGE (KERN_WARNING, device, + "successful ERP - dequeue and free request %p", + (void *) erp_done); +#endif /* ERP_DEBUG */ + + check_then_set (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, + erp_done); + + erp_free = erp_done; + erp_done = erp_done->refers; + + /* free the finished erp request */ + dasd_free_request (erp_free); + + } + + if (erp_done == NULL) /* erp_done should never be NULL! */ + panic (PRINTK_HEADER "Programming error in ERP! The original " + "request was lost\n"); + +#ifdef ERP_DEBUG + /* handle matching ERP */ + DASD_MESSAGE (KERN_WARNING, device, + "handle matching erp %p", + (void *) erp_done); +#endif + + if (erp_done->retries > 0) { + + /* check for special retries */ + if (erp_done->function == dasd_3990_erp_action_4) { + char *sense = erp_done->dstat->ii.sense.data; + erp_done = dasd_3990_erp_action_4 (erp_done, + sense); + + } else if (erp_done->function == dasd_3990_erp_action_1B_32) { + char *sense = erp_done->dstat->ii.sense.data; + erp_done = dasd_3990_update_1B (erp_done, + sense); + +#ifdef ERP_FULL_ERP + } else if (erp_done->function == dasd_3990_erp_int_req) { + erp_done = dasd_3990_erp_int_req (erp_done); +#endif /* ERP_FULL_ERP */ + + } else { + /* simple retry */ + DASD_MESSAGE (KERN_WARNING, device, + "%i retries left for erp %p", + erp_done->retries, + (void *) erp_done); + + /* handle the request again... */ + check_then_set (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } else { + /* no retry left - check for further necessary action */ + /* if no further actions, handle rest as permanent error */ + erp_done = dasd_3990_erp_further_erp (erp_done); + } + + erp_head = erp_done; + +} /* end dasd_3990_erp_handle_match_erp */ + +/* + * DASD_3990_ERP_ACTION + * + * DESCRIPTION + * controll routine for 3990 erp actions. + * Has to be called with the queue lock (namely the s390_irq_lock) acquired. + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the head of the ERP action chain. + * This means: + * - either a ptr to an additional ERP cqr or + * - the original given cqr (which's status might be modified) + */ +ccw_req_t * +dasd_3990_erp_action (ccw_req_t *cqr) +{ + ccw_req_t *erp = NULL; + dasd_device_t *device = cqr->device; + +#ifdef ERP_DEBUG + __u32 cpa = cqr->dstat->cpa; +#endif /* ERP_DEBUG */ + +#ifdef ERP_DEBUG + + printk (KERN_WARNING PRINTK_HEADER + "entering 3990 ERP for " + "0x%04X on sch %d = /dev/%s \n", + device->devinfo.devno, + device->devinfo.irq, + device->name); + + /* print current erp_chain */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "ERP chain at BEGINNING of ERP-ACTION"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = cqr; + temp_erp != NULL; + temp_erp = temp_erp->refers){ + + DASD_MESSAGE (KERN_WARNING, device, + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif + + /* double-check if current erp/cqr was successfull */ + if ((cqr->dstat->cstat == 0x00) && + (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called for successful request %p" + " - NO ERP necessary", + cqr); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + return cqr; + } + /* check if sense data are available */ + if (!cqr->dstat->ii.sense.data) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called witout sense data avail ..." + "request %p - NO ERP possible", + cqr); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return cqr; + + } + + /* check if error happened before */ + erp = dasd_3990_erp_in_erp (cqr); + + if (erp == NULL) { + /* no matching erp found - set up erp */ + erp = dasd_3990_erp_additional_erp (cqr); + } else { + /* matching erp found - set all leading erp's to DONE */ + dasd_3990_erp_handle_match_erp (cqr, erp); + erp = cqr; + } + +#ifdef ERP_DEBUG + /* print current erp_chain */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "ERP chain at END of ERP-ACTION"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; + temp_erp != NULL; + temp_erp = temp_erp->refers){ + + DASD_MESSAGE (KERN_WARNING, device, + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif /* ERP_DEBUG */ + +#ifdef ERP_DEBUG + if (erp->status == CQR_STATUS_FAILED) { + log_erp_chain (erp, 1, cpa); + } +#endif /* ERP_DEBUG */ - } /* end distinguish between 24 and 32 byte sense data */ + return erp; -} /* END dasd_3990_erp_examine */ +} /* end dasd_3990_erp_action */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_3990_erp.h linux/drivers/s390/block/dasd_3990_erp.h --- v2.4.3/linux/drivers/s390/block/dasd_3990_erp.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/dasd_3990_erp.h Wed Apr 11 19:02:28 2001 @@ -1,17 +1,28 @@ -ccw_req_t *dasd_3990_erp_com_rej (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_int_req (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_bus_out (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_equip_check (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_data_check (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_overrun (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_inv_format (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_EOC (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_env_data (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_no_rec (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_file_prot (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_perm (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_first_log (ccw_req_t *, devstat_t *); -ccw_req_t *dasd_3990_erp_add_erp (ccw_req_t *, devstat_t *); /* tbd - delete */ +/* + * File...........: linux/drivers/s390/block/dasd_3990_erp.h + * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_3990_ERP_H +#define DASD_3990_ERP_H + + +dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *); ccw_req_t *dasd_3990_erp_action (ccw_req_t *); ccw_req_t *dasd_2105_erp_action (ccw_req_t *); + +void dasd_3990_erp_restart_queue (unsigned long); + +typedef struct DCTL_data_t { + unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ + unsigned char modifier; /* Subcommand modifier */ + unsigned short res; /* reserved */ +} __attribute__ ((packed)) DCTL_data_t; + + +#endif /* DASD_3990_ERP_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_9343_erp.h linux/drivers/s390/block/dasd_9343_erp.h --- v2.4.3/linux/drivers/s390/block/dasd_9343_erp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/block/dasd_9343_erp.h Wed Apr 11 19:02:28 2001 @@ -0,0 +1,18 @@ +/* + * File...........: linux/drivers/s390/block/dasd_9343_erp.h + * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_9343_ERP_H +#define DASD_9343_ERP_H + + +dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *); + +ccw_req_t *dasd_9343_erp_action (ccw_req_t *); + +#endif /* DASD_9343_ERP_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c --- v2.4.3/linux/drivers/s390/block/dasd_diag.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/dasd_diag.c Wed Apr 11 19:02:28 2001 @@ -10,6 +10,8 @@ * 07/13/00 Added fixup sections for diagnoses ans saved some registers * 07/14/00 fixed constraints in newly generated inline asm * 10/05/00 adapted to 'new' DASD driver + * fixed return codes of dia250() + * fixed partition handling and HDIO_GETGEO */ #include <linux/stddef.h> @@ -73,10 +75,11 @@ static __inline__ int dia250 (void *iob, int cmd) { - int rc; - - __asm__ __volatile__ (" lr 1,%1\n" - " diag 1,%2,0x250\n" + __asm__ __volatile__ (" lr 0,%1\n" + " diag 0,%0,0x250\n" + "0: ipm %0\n" + " srl %0,28\n" + " or %0,1\n" "1:\n" ".section .fixup,\"ax\"\n" "2: lhi %0,3\n" @@ -87,12 +90,12 @@ ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 1b,2b\n" - ".previous\n" - :"=d" (rc) - :"d" ((void *) __pa (iob)), "0" (cmd) - :"1"); - return rc; + " .long 0b,2b\n" + ".previous\n" + : "+d" (cmd) + : "d" ((void *) __pa (iob)) + : "0", "1", "cc" ); + return cmd; } static __inline__ int @@ -112,7 +115,7 @@ rc = dia250 (iib, INIT_BIO); - return rc; + return rc&3; } static __inline__ int @@ -125,7 +128,7 @@ memset (iib, 0, sizeof (diag_init_io_t)); iib->dev_nr = device->devinfo.devno; rc = dia250 (iib, TERM_BIO); - return rc; + return rc&3; } int @@ -153,7 +156,12 @@ check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_ERROR); - } else { + } else if (rc == 0 ) { + check_then_set(&cqr->status, + CQR_STATUS_QUEUED, + CQR_STATUS_DONE); + dasd_schedule_bh(device); + } else { if (cqr->expires) { cqr->expires += cqr->startclk; } @@ -250,13 +258,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } - if (device->private == NULL) { - device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + if (device->private != NULL) { + kfree (device->private); + } + device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); + if (device->private == NULL) { + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_diag_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); @@ -304,7 +313,7 @@ if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); - free_page(private->label); + free_page((long)private->label); kfree(private); device->private = NULL; return -ENOMEM; @@ -319,7 +328,7 @@ memset (iob, 0, sizeof (diag_rw_io_t)); iob->dev_nr = rdc_data->dev_nr; iob->block_count = 1; - iob->interrupt_params = cqr; + iob->interrupt_params = (u32)cqr; iob->bio_list = __pa (bio); rc = dia250 (iob, RW_BIO); if (rc == 0) { @@ -354,19 +363,26 @@ static int dasd_diag_do_analysis (struct dasd_device_t *device) { - int sb; dasd_diag_private_t *private = (dasd_diag_private_t *) device->private; long *label = private->label; /* real size of the volume */ device->sizes.blocks = label[7]; + if (private->rdc_data.vdev_class == DEV_CLASS_FBA) { + device->sizes.pt_block = 1; + } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD || + private->rdc_data.vdev_class == DEV_CLASS_CKD) { + device->sizes.pt_block = 2; + } else { + return -EINVAL; + } printk (KERN_INFO PRINTK_HEADER "/dev/%s (%04X): capacity (%dkB blks): %ldkB\n", device->name, device->devinfo.devno, (device->sizes.bp_block >> 10), (device->sizes.blocks << device->sizes.s2b_shift) >> 1); - free_page(private->label); + free_page((long)private->label); return 0; } @@ -393,14 +409,6 @@ geo->cylinders = cyls; geo->heads = 16; geo->sectors = 128 >> device->sizes.s2b_shift; - if (private->rdc_data.vdev_class == DEV_CLASS_FBA) { - geo->start = 1; - } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD || - private->rdc_data.vdev_class == DEV_CLASS_CKD) { - geo->start = 2; - } else { - return -EINVAL; - } return rc; } @@ -482,7 +490,7 @@ } } rw_cp->device = device; - rw_cp->expires = 5 * 0xf424000; /* 5 seconds */ + rw_cp->expires = 50 * TOD_SEC; /* 50 seconds */ rw_cp->req = req; check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED); return rw_cp; @@ -507,6 +515,7 @@ { name:"DIAG", ebcname:"DIAG", + max_blocks:PAGE_SIZE/sizeof(diag_bio_t), check_characteristics:dasd_diag_check_characteristics, do_analysis:dasd_diag_do_analysis, fill_geometry:dasd_diag_fill_geometry, diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c --- v2.4.3/linux/drivers/s390/block/dasd_eckd.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/dasd_eckd.c Wed Apr 11 19:02:28 2001 @@ -15,6 +15,8 @@ * 10/10/00 reverted last change according to ESS exploitation * 10/10/00 now dequeuing init_cqr before freeing *ouch* * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF) + * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC + * fixed partition handling and HDIO_GETGEO */ #include <linux/config.h> @@ -40,6 +42,8 @@ #undef PRINTK_HEADER #endif /* PRINTK_HEADER */ #define PRINTK_HEADER DASD_NAME"(eckd): " +#undef DASD_CDL // Support compatible disk layout +#undef CDL_PRINTK #define ECKD_C0(i) (i->home_bytes) #define ECKD_F(i) (i->formula) @@ -52,36 +56,21 @@ #define ECKD_F7(i) (i->factor7) #define ECKD_F8(i) (i->factor8) -#define DASD_ECKD_CCW_WRITE 0x05 -#define DASD_ECKD_CCW_READ 0x06 -#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 -#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a -#define DASD_ECKD_CCW_WRITE_KD 0x0d -#define DASD_ECKD_CCW_READ_KD 0x0e -#define DASD_ECKD_CCW_READ_COUNT 0x12 -#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 -#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 -#define DASD_ECKD_CCW_WRITE_CKD 0x1d -#define DASD_ECKD_CCW_READ_CKD 0x1e -#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 -#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 -#define DASD_ECKD_CCW_WRITE_MT 0x85 -#define DASD_ECKD_CCW_READ_MT 0x86 -#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d -#define DASD_ECKD_CCW_READ_KD_MT 0x8e -#define DASD_ECKD_CCW_RELEASE 0x94 -#define DASD_ECKD_CCW_READ_CKD_MT 0x9e -#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d -#define DASD_ECKD_CCW_RESERVE 0xB4 - dasd_discipline_t dasd_eckd_discipline; typedef struct dasd_eckd_private_t { dasd_eckd_characteristics_t rdc_data; dasd_eckd_confdata_t conf_data; +#ifdef DASD_CDL + eckd_count_t count_area[5]; +#else eckd_count_t count_area; +#endif ccw_req_t *init_cqr; +#ifdef DASD_CDL + int uses_cdl; +#endif } dasd_eckd_private_t; #ifdef CONFIG_DASD_DYNAMIC @@ -91,27 +80,38 @@ { ci: {hc: - {ctype:0x3990, dtype:0x3390}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x3990}}, + flag: (DEVREG_MATCH_CU_TYPE | + DEVREG_NO_DEV_INFO| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler }, { ci: {hc: - {ctype:0x3990, dtype:0x3380}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x2105}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_NO_DEV_INFO| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler }, { ci: {hc: - {ctype:0x9343, dtype:0x9345}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x9343}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_NO_DEV_INFO| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler } }; #endif +#ifdef DASD_CDL +int sizes_trk0[]={28,148,84}; +#define LABEL_SIZE 140 +#endif + static inline unsigned int round_up_multiple (unsigned int no, unsigned int mult) { @@ -210,6 +210,7 @@ return rpt; } + static inline void define_extent (ccw1_t * de_ccw, DE_eckd_data_t * data, @@ -269,7 +270,11 @@ break; } data->attributes.mode = 0x3; - if (private->rdc_data.cu_type == 0x2105) { + if (private->rdc_data.cu_type == 0x2105 +#ifdef DASD_CDL + && !(private->uses_cdl && trk < 2) +#endif + ) { data->reserved |= 0x40; } data->beg_ext.cyl = beg.cyl; @@ -296,6 +301,9 @@ {trk / (geo.head), trk % (geo.head)}; int sector; +#ifdef CDL_PRINTK + printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n",trk,rec_on_trk,no_rec,cmd,reclen); +#endif memset (lo_ccw, 0, sizeof (ccw1_t)); lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; lo_ccw->count = 16; @@ -411,13 +419,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if (device->private != NULL) { + kfree(device->private); + } + device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL); if (device->private == NULL) { - device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_eckd_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); @@ -468,6 +477,22 @@ return 0; } +#ifdef DASD_CDL +static inline int +dasd_eckd_cdl_reclen (dasd_device_t* device,int recid) { + dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; + int byt_per_blk = device->sizes.bp_block; + int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); + if (recid < 3) + return sizes_trk0[recid]; + if (recid < blk_per_trk) + return byt_per_blk; + if (recid < 2*blk_per_trk ) + return LABEL_SIZE; + return byt_per_blk; +} +#endif + static ccw_req_t * dasd_eckd_init_analysis (struct dasd_device_t *device) { @@ -476,9 +501,20 @@ DE_eckd_data_t *DE_data; LO_eckd_data_t *LO_data; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; +#ifdef DASD_CDL + eckd_count_t *count_data = private->count_area; +#else eckd_count_t *count_data = &(private->count_area); - - cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); +#endif +#ifdef DASD_CDL + cqr = ccw_alloc_request (dasd_eckd_discipline.name, 8 + 1, + sizeof (DE_eckd_data_t) + + 2*sizeof (LO_eckd_data_t)); +#else + cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); +#endif if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -489,72 +525,159 @@ DE_data = cqr->data; LO_data = cqr->data + sizeof (DE_eckd_data_t); ccw = cqr->cpaddr; +#ifdef DASD_CDL + define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device); +#else define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device); +#endif ccw->flags |= CCW_FLAG_CC; ccw++; +#ifdef DASD_CDL + locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, device, 0); +#else locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); +#endif +#ifdef DASD_CDL ccw->flags |= CCW_FLAG_CC; ccw++; ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data)); + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data++)); + ccw->flags |= CCW_FLAG_CC; + ccw++; + locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); +#endif + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + set_normalized_cda (ccw, __pa (count_data)); cqr->device = device; cqr->retries = 0; cqr->status = CQR_STATUS_FILLED; - return cqr; } static int dasd_eckd_do_analysis (struct dasd_device_t *device) { - int rc = 0; int sb, rpt; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - int bs = private->count_area.dl; - + eckd_count_t *count_area = NULL; + char *cdl_msg; +#ifdef DASD_CDL /* BAD HACK SO FIX ME UP */ + int i; + private -> uses_cdl = 1; + + /* Free the cqr and cleanup device->sizes */ + dasd_chanq_deq (&device->queue, private->init_cqr); + ccw_free_request (private->init_cqr); + private->init_cqr = NULL; + memset (&(device->sizes), 0, sizeof (dasd_sizes_t)); + /* Check Track 0 for Compatible Disk Layout */ + for (i = 0; i < 3; i++) { + if ((i < 3) && + ((private->count_area[i].kl != 4) || + (private->count_area[i].dl != + dasd_eckd_cdl_reclen (device,i) - 4))) { + private -> uses_cdl = 0; + break; + } + } + if ( i == 3 ) { + count_area = &private->count_area[4]; + } + if (private->uses_cdl == 0) { + for (i = 0; i < 5; i++) { + if ((private->count_area[i].kl != 0) || + (private->count_area[i].dl != + private->count_area[0].dl)) { + break; + } + } + if ( i == 5 ) { + count_area = &private->count_area[0]; + } + } else { + if (private->count_area[3].record == 1) { + DASD_MESSAGE(KERN_WARNING,device,"%s", + "Trk 0: no records after VTOC!"); + } + } + if (count_area != NULL && /* we found notthing violating our disk layout */ + count_area ->kl == 0) { + /* find out blocksize */ + switch (count_area->dl) { + case 512: + case 1024: + case 2048: + case 4096: + device->sizes.bp_block = count_area->dl; + break; + } + } +#else dasd_chanq_deq (&device->queue, private->init_cqr); ccw_free_request (private->init_cqr); private->init_cqr = NULL; memset (&(device->sizes), 0, sizeof (dasd_sizes_t)); - switch (bs) { + switch (private->count_area.dl) { case 512: case 1024: case 2048: case 4096: - device->sizes.bp_block = bs; + device->sizes.bp_block = private->count_area.dl; break; - default: - printk (KERN_INFO PRINTK_HEADER - "/dev/%s (%04X): invalid blocksize %d\n" - KERN_INFO PRINTK_HEADER - "/dev/%s (%04X): capacity (at 4kB blks): %dkB at %dkB/trk\n", - device->name, device->devinfo.devno, bs, - device->name, device->devinfo.devno, - (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, 4096)), - recs_per_track (&private->rdc_data, 0, 4096)); - return -EMEDIUMTYPE; } +#endif + if ( device->sizes.bp_block == 0 ) { + DASD_MESSAGE(KERN_WARNING, device,"%s\n", + "Volume has incompatible disk layout"); + return -EMEDIUMTYPE; + } device->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */ - for (sb = 512; sb < bs; sb = sb << 1) + device->sizes.pt_block = 2; + for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1) device->sizes.s2b_shift++; rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block); - device->sizes.blocks = (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, device->sizes.bp_block)); - - printk (KERN_INFO PRINTK_HEADER - "/dev/%s (%04X): capacity (%dkB blks): %dkB at %dkB/trk\n", - device->name, device->devinfo.devno, - (device->sizes.bp_block >> 10), - (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, device->sizes.bp_block) * - (device->sizes.bp_block >> 9)) >> 1, - (recs_per_track (&private->rdc_data, 0, device->sizes.bp_block) * device->sizes.bp_block) >> 10); + device->sizes.blocks = (private->rdc_data.no_cyl * + private->rdc_data.trk_per_cyl * + recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block)); +#ifdef DASD_CDL + cdl_msg = private->uses_cdl?"compatible disk layout":"classic disk layout"; +#else + cdl_msg = "classic disk layout"; +#endif + + DASD_MESSAGE(KERN_INFO,device,"(%dkB blks): %dkB at %dkB/trk %s", + (device->sizes.bp_block >> 10), + (private->rdc_data.no_cyl * + private->rdc_data.trk_per_cyl * + recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block) * + (device->sizes.bp_block >> 9)) >> 1, + (recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block) * + device->sizes.bp_block) >> 10, + cdl_msg); return 0; - - return rc; } static int @@ -574,7 +697,6 @@ geo->cylinders = private->rdc_data.no_cyl; geo->heads = private->rdc_data.trk_per_cyl; geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block); - geo->start = 2; return rc; } @@ -600,6 +722,9 @@ int head = trk % private->rdc_data.trk_per_cyl; int wrccws = rpt; int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t); +#ifdef DASD_CDL + int formatCDL=0; +#endif if (((fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) && trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) || @@ -623,7 +748,15 @@ case 0x01: case 0x03: case 0x04: /* make track invalid */ + break; +#ifdef DASD_CDL /* Format compatible disk Layout */ + case 0x08: + case 0x09: + case 0x0b: + case 0x0c: + formatCDL=1; break; +#endif default: printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n", flags); return NULL; @@ -678,6 +811,7 @@ switch (flags) { case 0x03: + case 0x0b: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); last_ccw->flags |= CCW_FLAG_CC; @@ -688,6 +822,7 @@ last_ccw++; break; case 0x01: + case 0x09: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); last_ccw->flags |= CCW_FLAG_CC; @@ -699,6 +834,7 @@ memset (r0_data, 0, sizeof (eckd_count_t)); break; case 0x00: + case 0x08: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_CKD, device); last_ccw->flags |= CCW_FLAG_CC; @@ -710,6 +846,7 @@ last_ccw++; break; case 0x04: + case 0x0c: define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_CKD, device); last_ccw->flags |= CCW_FLAG_CC; @@ -747,7 +884,29 @@ (ct_data + i)->head = head; (ct_data + i)->record = i + 1; (ct_data + i)->kl = 0; - (ct_data + i)->dl = bs; +#ifdef DASD_CDL + if (formatCDL) { + // special handling when formatting CDL + switch (trk) { + case 0: + if (i<3) { + (ct_data + i)->kl = 4; + (ct_data + i)->dl = sizes_trk0[i]-4; + } else + (ct_data + i)->dl = bs; + break; + case 1: + (ct_data + i)->kl = 44; + (ct_data + i)->dl = LABEL_SIZE-44; + break; + default: + (ct_data + i)->dl = bs; + break; + } + } + else +#endif + (ct_data + i)->dl = bs; last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI; last_ccw->count = 8; @@ -791,7 +950,7 @@ switch (device->devinfo.sid_data.cu_type) { case 0x3990: case 0x2105: - /* return dasd_3990_erp_action; */ + return dasd_3990_erp_action; case 0x9343: /* Return dasd_9343_erp_action; */ default: @@ -802,13 +961,42 @@ static dasd_erp_postaction_fn_t dasd_eckd_erp_postaction (ccw_req_t * cqr) { - if (cqr->function != default_erp_action) - printk (KERN_WARNING PRINTK_HEADER - "unknown ERP action [<%p>]\n", - cqr->function); return default_erp_postaction; } + +#ifdef DASD_CDL +inline unsigned char +dasd_eckd_cdl_cmd(dasd_device_t *device,int recid,int cmd) { + dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; + int byt_per_blk = device->sizes.bp_block; + int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); + switch (cmd) { + case READ: + if (recid < 3) + return DASD_ECKD_CCW_READ_KD_MT; + if (recid < blk_per_trk) + return DASD_ECKD_CCW_READ_MT; + if (recid < 2*blk_per_trk) + return DASD_ECKD_CCW_READ_KD_MT; + return DASD_ECKD_CCW_READ_MT; + break; + case WRITE: + if (recid < 3) + return DASD_ECKD_CCW_WRITE_KD_MT; + if (recid < blk_per_trk) + return DASD_ECKD_CCW_WRITE_MT; + if (recid < 2*blk_per_trk) + return DASD_ECKD_CCW_WRITE_KD_MT; + return DASD_ECKD_CCW_WRITE_MT; + break; + default: + BUG(); + } + return 0; // never executed +} +#endif + static ccw_req_t * dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req) { @@ -826,6 +1014,11 @@ int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); int btrk = (req->sector >> shift) / blk_per_trk; int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk; +#ifdef DASD_CDL + int recid = req->sector >> shift; + int locate4k_set=0; + int nlocs=0; +#endif if (req->cmd == READ) { rw_cmd = DASD_ECKD_CCW_READ_MT; @@ -845,43 +1038,123 @@ else bhct++; } - +#ifndef DASD_CDL rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 2 + bhct + 1, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); +#else + if (btrk<2 && private->uses_cdl) { + nlocs+= 2*blk_per_trk-recid; + if (etrk<2) + nlocs-=2*blk_per_trk-((req->sector + req->nr_sectors - 1) >> shift); + } + rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, + 2 + nlocs + bhct + 1, + sizeof (DE_eckd_data_t) + + (1+nlocs)*sizeof (LO_eckd_data_t)); +#endif if (!rw_cp) { return NULL; } DE_data = rw_cp->data; LO_data = rw_cp->data + sizeof (DE_eckd_data_t); ccw = rw_cp->cpaddr; - define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device); ccw->flags |= CCW_FLAG_CC; +#ifndef DASD_CDL ccw++; - locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, - req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block); + locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, + req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block); ccw->flags |= CCW_FLAG_CC; +#endif for (bh = req->bh; bh != NULL;) { if (bh->b_size > byt_per_blk) { for (size = 0; size < bh->b_size; size += byt_per_blk) { +#ifdef DASD_CDL + if (!locate4k_set) { + // we need to chain a locate record before our rw-ccw + ccw++; + if ((recid/blk_per_trk)<2 && private->uses_cdl) { + /* Do a locate record for our special blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, 1, + dasd_eckd_cdl_cmd(device,recid,req->cmd), + device, + dasd_eckd_cdl_reclen(device,recid)); + } else { + // Do a locate record for standard blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, + (((req->sector + req->nr_sectors) >> shift)-recid), + rw_cmd,device, device->sizes.bp_block); + locate4k_set=1; + } + ccw->flags |= CCW_FLAG_CC; + } +#endif ccw++; +#ifndef DASD_CDL ccw->flags |= CCW_FLAG_CC; - ccw->cmd_code = rw_cmd; - ccw->count = byt_per_blk; - set_normalized_cda (ccw, __pa (bh->b_data + size)); + ccw->cmd_code= rw_cmd; + ccw->count = bh->b_size; +#else + ccw->flags |= CCW_FLAG_CC; + ccw->cmd_code=locate4k_set?rw_cmd: + dasd_eckd_cdl_cmd(device,recid,req->cmd); + ccw->count =locate4k_set?bh->b_size: + dasd_eckd_cdl_reclen(device,recid); +#endif + set_normalized_cda (ccw, __pa (bh->b_data)); + size += bh->b_size; + bh = bh->b_reqnext; +#ifdef DASD_CDL + recid++; +#endif } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { +#ifdef DASD_CDL + if (!locate4k_set) { + // we need to chain a locate record before our rw-ccw + ccw++; + if ((recid/blk_per_trk)<2 && private->uses_cdl) { + /* Do a locate record for our special blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, 1, + dasd_eckd_cdl_cmd(device,recid,req->cmd), + device, + dasd_eckd_cdl_reclen(device,recid)); + } else { + // Do a locate record for standard blocks */ + locate_record (ccw, LO_data++, recid/blk_per_trk, + recid % blk_per_trk + 1, + (((req->sector + req->nr_sectors) >> shift)-recid), + rw_cmd,device, device->sizes.bp_block); + locate4k_set=1; + } + ccw->flags |= CCW_FLAG_CC; + } +#endif ccw++; +#ifndef DASD_CDL ccw->flags |= CCW_FLAG_DC; - ccw->cmd_code = rw_cmd; + ccw->cmd_code= rw_cmd; ccw->count = bh->b_size; +#else + ccw->flags |= locate4k_set?CCW_FLAG_DC:CCW_FLAG_CC; + ccw->cmd_code=locate4k_set?rw_cmd: + dasd_eckd_cdl_cmd(device,recid,req->cmd); + ccw->count =locate4k_set?bh->b_size: + dasd_eckd_cdl_reclen(device,recid); +#endif set_normalized_cda (ccw, __pa (bh->b_data)); size += bh->b_size; bh = bh->b_reqnext; +#ifdef DASD_CDL + recid++; +#endif } if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", @@ -1000,14 +1273,13 @@ ccw_req_t * dasd_eckd_merge_cp ( dasd_device_t *device ) { - ccw_req_t * cqr; return NULL; } static char * dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req) { - char *page = (char *) get_free_page (GFP_KERNEL); + char *page = (char *) get_free_page (GFP_ATOMIC); devstat_t *stat = &device->dev_status; char *sense = stat->ii.sense.data; int len, sl, sct; @@ -1027,13 +1299,13 @@ ccw1_t *act = req -> cpaddr; int i = req -> cplength; do { -#if 0 +#ifdef ERP_DEBUB printk ( KERN_INFO "CCW %p: %08X %08X\n", act,((int*)act)[0],((int*)act)[1]); printk ( KERN_INFO "DAT: %08X %08X %08X %08X\n", ((int*)act->cda)[0],((int*)act->cda)[1], ((int*)act->cda)[2],((int*)act->cda)[3]); -#endif +#endif /* ERP_DEBUG */ act ++; } while ( --i ); } @@ -1071,6 +1343,7 @@ { name:"ECKD", ebcname:"ECKD", + max_blocks:255, id_check:dasd_eckd_id_check, check_characteristics:dasd_eckd_check_characteristics, init_analysis:dasd_eckd_init_analysis, @@ -1101,14 +1374,12 @@ { int i; for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) { - printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + printk (KERN_INFO PRINTK_HEADER + "We are interested in: CU %04X/%02x\n", dasd_eckd_known_devices[i].ci.hc.ctype, - dasd_eckd_known_devices[i].ci.hc.cmode, - dasd_eckd_known_devices[i].ci.hc.dtype, - dasd_eckd_known_devices[i].ci.hc.dmode); + dasd_eckd_known_devices[i].ci.hc.cmode); s390_device_register (&dasd_eckd_known_devices[i]); - } + } } #endif /* CONFIG_DASD_DYNAMIC */ return rc; @@ -1123,12 +1394,10 @@ int i; for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + "We were interested in: CU %04X/%02x\n", dasd_eckd_known_devices[i].ci.hc.ctype, - dasd_eckd_known_devices[i].ci.hc.cmode, - dasd_eckd_known_devices[i].ci.hc.dtype, - dasd_eckd_known_devices[i].ci.hc.dmode); - s390_device_register(&dasd_eckd_known_devices[i]); + dasd_eckd_known_devices[i].ci.hc.cmode); + s390_device_unregister(&dasd_eckd_known_devices[i]); } } #endif /* CONFIG_DASD_DYNAMIC */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h --- v2.4.3/linux/drivers/s390/block/dasd_eckd.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/dasd_eckd.h Wed Apr 11 19:02:28 2001 @@ -2,8 +2,32 @@ #define DASD_ECKD_H #include "dasd_3990_erp.h" +#include "dasd_9343_erp.h" -typedef +#define DASD_ECKD_CCW_WRITE 0x05 +#define DASD_ECKD_CCW_READ 0x06 +#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 +#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a +#define DASD_ECKD_CCW_WRITE_KD 0x0d +#define DASD_ECKD_CCW_READ_KD 0x0e +#define DASD_ECKD_CCW_READ_COUNT 0x12 +#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 +#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 +#define DASD_ECKD_CCW_WRITE_CKD 0x1d +#define DASD_ECKD_CCW_READ_CKD 0x1e +#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 +#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 +#define DASD_ECKD_CCW_WRITE_MT 0x85 +#define DASD_ECKD_CCW_READ_MT 0x86 +#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d +#define DASD_ECKD_CCW_READ_KD_MT 0x8e +#define DASD_ECKD_CCW_RELEASE 0x94 +#define DASD_ECKD_CCW_READ_CKD_MT 0x9e +#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d +#define DASD_ECKD_CCW_RESERVE 0xB4 + + +typedef struct eckd_count_t { __u16 cyl; __u16 head; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c --- v2.4.3/linux/drivers/s390/block/dasd_fba.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/dasd_fba.c Wed Apr 11 19:02:28 2001 @@ -4,6 +4,7 @@ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * fixed partition handling and HDIO_GETGEO */ #include <linux/config.h> @@ -49,15 +50,21 @@ { ci: {hc: - {ctype:0x6310, dtype:0x9336}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x6310, + dtype:0x9336}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_MATCH_DEV_TYPE| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler }, { ci: {hc: - {ctype:0x3880, dtype:0x3370}}, - flag:DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + {ctype:0x3880, + dtype:0x3370}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_MATCH_DEV_TYPE| + DEVREG_TYPE_DEVCHARS), oper_func:dasd_oper_handler } }; @@ -123,13 +130,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL); if (device->private == NULL) { - device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_fba_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); @@ -179,6 +187,7 @@ device->sizes.s2b_shift++; device->sizes.blocks = (private->rdc_data.blk_bdsa); + device->sizes.pt_block = 1; return rc; } @@ -203,7 +212,6 @@ geo->cylinders = cyls; geo->heads = 16; geo->sectors = 128 >> device->sizes.s2b_shift; - geo->start = 1; return rc; } @@ -247,7 +255,7 @@ { ccw_req_t *rw_cp = NULL; int rw_cmd; - int bhct; + int bhct, i; long size; ccw1_t *ccw; DE_fba_data_t *DE_data; @@ -276,9 +284,9 @@ } rw_cp = dasd_alloc_request (dasd_fba_discipline.name, - 2 + bhct, + 1 + 2*bhct, sizeof (DE_fba_data_t) + - sizeof (LO_fba_data_t)); + bhct*sizeof (LO_fba_data_t)); if (!rw_cp) { return NULL; } @@ -289,29 +297,30 @@ define_extent (ccw, DE_data, req->cmd, byt_per_blk, req->sector, req->nr_sectors); ccw->flags |= CCW_FLAG_CC; - ccw++; - locate_record (ccw, LO_data, req->cmd, 0, req->nr_sectors); - ccw->flags |= CCW_FLAG_CC; - for (bh = req->bh; bh;) { + for (i = 0, bh = req->bh; bh;) { if (bh->b_size > byt_per_blk) { for (size = 0; size < bh->b_size; size += byt_per_blk) { + ccw++; + locate_record (ccw, LO_data, req->cmd, i, 1); + ccw->flags |= CCW_FLAG_CC; ccw++; - if (private->rdc_data.mode.bits.data_chain) { - ccw->flags |= CCW_FLAG_DC; - } else { - ccw->flags |= CCW_FLAG_CC; - } + ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI; ccw->cmd_code = rw_cmd; ccw->count = byt_per_blk; set_normalized_cda (ccw, __pa (bh->b_data + size)); + i++; + LO_data++; } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { + ccw++; + locate_record (ccw, LO_data, req->cmd, i, 1); + ccw->flags |= CCW_FLAG_CC; ccw++; if (private->rdc_data.mode.bits.data_chain) { - ccw->flags |= CCW_FLAG_DC; + ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI; } else { PRINT_WARN ("Cannot chain chunks smaller than one block\n"); ccw_free_request (rw_cp); @@ -322,9 +331,11 @@ set_normalized_cda (ccw, __pa (bh->b_data)); size += bh->b_size; bh = bh->b_reqnext; + i++; + LO_data++; } ccw->flags &= ~CCW_FLAG_DC; - ccw->flags |= CCW_FLAG_CC; + ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI; if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill request smaller than block\n"); ccw_free_request (rw_cp); @@ -360,6 +371,7 @@ { name:"FBA ", ebcname:"FBA ", + max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1), id_check:dasd_fba_id_check, check_characteristics:dasd_fba_check_characteristics, do_analysis:dasd_fba_do_analysis, @@ -387,11 +399,9 @@ int i; for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + "We are interested in: CU %04X/%02x\n", dasd_fba_known_devices[i].ci.hc.ctype, - dasd_fba_known_devices[i].ci.hc.cmode, - dasd_fba_known_devices[i].ci.hc.dtype, - dasd_fba_known_devices[i].ci.hc.dmode); + dasd_fba_known_devices[i].ci.hc.cmode); s390_device_register (&dasd_fba_known_devices[i]); } } @@ -408,12 +418,10 @@ int i; for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n", + "We were interested in: CU %04X/%02x\n", dasd_fba_known_devices[i].ci.hc.ctype, - dasd_fba_known_devices[i].ci.hc.cmode, - dasd_fba_known_devices[i].ci.hc.dtype, - dasd_fba_known_devices[i].ci.hc.dmode); - s390_device_register(&dasd_fba_known_devices[i]); + dasd_fba_known_devices[i].ci.hc.cmode); + s390_device_unregister(&dasd_fba_known_devices[i]); } } #endif /* CONFIG_DASD_DYNAMIC */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c --- v2.4.3/linux/drivers/s390/block/xpram.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/block/xpram.c Wed Apr 11 19:02:28 2001 @@ -658,7 +658,7 @@ case BLKFLSBUF: /* flush, 0x1261 */ fsync_dev(inode->i_rdev); - if ( suser() )invalidate_buffers(inode->i_rdev); + if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev); return 0; case BLKRAGET: /* return the readahead value, 0x1263 */ @@ -671,7 +671,7 @@ return 0; case BLKRASET: /* set the readahead value, 0x1262 */ - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg > 0xff) return -EINVAL; /* limit it */ read_ahead[MAJOR(inode->i_rdev)] = arg; atomic_eieio(); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c --- v2.4.3/linux/drivers/s390/ccwcache.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/ccwcache.c Wed Apr 11 19:02:28 2001 @@ -9,6 +9,7 @@ * 11/14/00 redesign by Martin Schwidefsky */ +#include <linux/module.h> #include <linux/malloc.h> #include <linux/version.h> @@ -31,9 +32,7 @@ #define kmem_cache_destroy(x) do {} while(0) #endif -#ifdef PRINTK_HEADER #undef PRINTK_HEADER -#endif #define PRINTK_HEADER "ccwcache" /* pointer to list of allocated requests */ @@ -300,4 +299,7 @@ } debug_unregister( debug_area ); } + +EXPORT_SYMBOL(ccw_alloc_request); +EXPORT_SYMBOL(ccw_free_request); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/Makefile linux/drivers/s390/char/Makefile --- v2.4.3/linux/drivers/s390/char/Makefile Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/Makefile Wed Apr 11 19:02:29 2001 @@ -1,33 +1,42 @@ -all: s390-char.o +# Makefile for the S/390 supported character devices +# +# 4 January 2001 Richard Hitt +# Modeled after similar files of Michael Elizabeth Chastain +# Rewritten to use lists instead of if-statements. -CFLAFS += -O_TARGET := s390-char.o +O_TARGET := s390-char.o -obj-$(CONFIG_3215_CONSOLE) += con3215.o +export-objs := +list-multi := tub3270.o tape390.o -obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o +obj-y := +obj-m := +obj-n := +obj- := -# stuff for building tape390.o -T390_OBJS = tape.o -ifeq ($(CONFIG_S390_TAPE_CHAR),y) - T390_OBJS += tapechar.o -endif -ifeq ($(CONFIG_S390_TAPE_BLOCK),y) - T390_OBJS += tapeblock.o -endif -ifeq ($(CONFIG_S390_TAPE_3480),y) - T390_OBJS += tape3480.o - CONFIG_S390_TAPE_NEED_34xx = y -endif -ifeq ($(CONFIG_S390_TAPE_3490),y) - T390_OBJS += tape3490.o - CONFIG_S390_TAPE_NEED_34xx = y -endif -ifeq ($(CONFIG_S390_TAPE_NEED_34xx),y) - T390_OBJS += tape34xx.o -endif -obj-$(CONFIG_S390_TAPE) += tape390.o +tub3270-objs := tuball.o tubfs.o tubtty.o \ + tubttyaid.o tubttybld.o tubttyrcl.o \ + tubttyscl.o tubttysiz.o + +obj-y += ctrlchar.o +obj-$(CONFIG_3215_CONSOLE) += con3215.o +obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o +obj-$(CONFIG_3270) += tub3270.o + +tape-y := tape.o +tape-$(CONFIG_S390_TAPE_CHAR) += tapechar.o +tape-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o +tape-$(CONFIG_S390_TAPE_3480) += tape3480.o tape34xx.o +tape-$(CONFIG_S390_TAPE_3490) += tape3490.o tape34xx.o +tape390-objs := $(sort $(tape-y)) +obj-$(CONFIG_S390_TAPE) += tape390.o + +# Hand off to Rules.make. -tape390.o: $(T390_OBJS) - $(LD) -r -o $@ $(T390_OBJS) include $(TOPDIR)/Rules.make + +tub3270.o: $(tub3270-objs) + $(LD) -r -o $@ $(tub3270-objs) + +tape390.o: $(tape390-objs) + $(LD) -r -o $@ $(tape390-objs) diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c --- v2.4.3/linux/drivers/s390/char/con3215.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/con3215.c Wed Apr 11 19:02:29 2001 @@ -22,14 +22,17 @@ #include <linux/slab.h> #include <linux/bootmem.h> +#include <linux/devfs_fs_kernel.h> + #include <asm/io.h> #include <asm/ebcdic.h> #include <asm/uaccess.h> #include <asm/delay.h> - -#include "../../../arch/s390/kernel/cpcmd.h" +#include <asm/cpcmd.h> #include <asm/irq.h> +#include "ctrlchar.h" + #define NR_3215 1 #define NR_3215_REQ (4*NR_3215) #define RAW3215_BUFFER_SIZE 65536 /* output buffer size */ @@ -116,7 +119,7 @@ { int vdev; - vdev = simple_strtoul(str,&str,16); + vdev = simple_strtoul(str,&str,0); if (vdev >= 0 && vdev < 65536) raw3215_condevice = vdev; return 1; @@ -470,6 +473,8 @@ if ((raw = req->info) == NULL) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ && raw->tty != NULL) { + char *cchar; + tty = raw->tty; count = 160 - req->residual; if (MACHINE_IS_P390) { @@ -480,33 +485,12 @@ if (count >= TTY_FLIPBUF_SIZE - tty->flip.count) count = TTY_FLIPBUF_SIZE - tty->flip.count - 1; EBCASC(raw->inbuf, count); - if (count == 2 && ( - /* hat is 0xb0 in codepage 037 (US etc.) and thus */ - /* converted to 0x5e in ascii ('^') */ - strncmp(raw->inbuf, "^c", 2) == 0 || - /* hat is 0xb0 in several other codepages (German,*/ - /* UK, ...) and thus converted to ascii octal 252 */ - strncmp(raw->inbuf, "\252c", 2) == 0) ) { - /* emulate a control C = break */ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = INTR_CHAR(tty); - tty_flip_buffer_push(raw->tty); - } else if (count == 2 && ( - strncmp(raw->inbuf, "^d", 2) == 0 || - strncmp(raw->inbuf, "\252d", 2) == 0) ) { - /* emulate a control D = end of file */ + if ((cchar = ctrlchar_handle(raw->inbuf, count, tty))) { + if (cchar == (char *)-1) + goto in_out; tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = EOF_CHAR(tty); - tty_flip_buffer_push(raw->tty); - } else if (count == 2 && ( - strncmp(raw->inbuf, "^z", 2) == 0 || - strncmp(raw->inbuf, "\252z", 2) == 0) ) { - /* emulate a control Z = suspend */ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = SUSP_CHAR(tty); + *tty->flip.char_buf_ptr++ = *cchar; tty_flip_buffer_push(raw->tty); } else { memcpy(tty->flip.char_buf_ptr, @@ -530,6 +514,7 @@ raw->count -= req->len; raw->written -= req->len; } +in_out: raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); /* check for empty wait */ @@ -794,22 +779,6 @@ #ifdef CONFIG_3215_CONSOLE /* - * Try to request the console IRQ. Called from init/main.c - */ -int con3215_activate(void) -{ - raw3215_info *raw; - - if (!MACHINE_IS_VM && !MACHINE_IS_P390) - return 0; - raw = raw3215[0]; /* 3215 console is the first one */ - if (raw == NULL || raw->irq == -1) - /* console device not found in con3215_init */ - return -1; - return raw3215_startup(raw); -} - -/* * Write a string to the 3215 console */ static void @@ -1092,12 +1061,10 @@ } } + /* - * 3215 console driver boottime initialization code. - * Register console. We can't request the IRQ here, because - * it's too early (kmalloc isn't working yet). We'll have to - * buffer all the console requests until we can request the - * irq. For this purpose we use some pages of fixed memory. + * 3215 console initialization code called from console_init(). + * NOTE: This is called before kmalloc is available. */ void __init con3215_init(void) { @@ -1121,6 +1088,8 @@ raw3215_freelist = req; } + ctrlchar_init(); + #ifdef CONFIG_3215_CONSOLE raw3215[0] = raw = (raw3215_info *) alloc_bootmem_low(sizeof(raw3215_info)); @@ -1135,6 +1104,10 @@ raw->tqueue.data = raw; init_waitqueue_head(&raw->empty_wait); + /* Request the console irq */ + if ( raw3215_startup(raw) != 0 ) + raw->irq = -1; + if (raw->irq != -1) { register_console(&con3215); } else { @@ -1145,7 +1118,16 @@ printk("Couldn't find a 3215 console device\n"); } #endif +} +/* + * 3215 tty registration code called from tty_init(). + * Most kernel services (incl. kmalloc) are available at this poimt. + */ +void __init tty3215_init(void) +{ + if (!MACHINE_IS_VM && !MACHINE_IS_P390) + return; /* * Initialize the tty_driver structure * Entries in tty3215_driver that are NOT initialized: @@ -1166,7 +1148,7 @@ tty3215_driver.init_termios.c_iflag = IGNBRK | IGNPAR; tty3215_driver.init_termios.c_oflag = ONLCR | XTABS; tty3215_driver.init_termios.c_lflag = ISIG; - tty3215_driver.flags = TTY_DRIVER_REAL_RAW; + tty3215_driver.flags = TTY_DRIVER_REAL_RAW; tty3215_driver.refcount = &tty3215_refcount; tty3215_driver.table = tty3215_table; tty3215_driver.termios = tty3215_termios; @@ -1194,5 +1176,4 @@ if (tty_register_driver(&tty3215_driver)) panic("Couldn't register tty3215 driver\n"); - } diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/ctrlchar.c linux/drivers/s390/char/ctrlchar.c --- v2.4.3/linux/drivers/s390/char/ctrlchar.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/ctrlchar.c Wed Apr 11 19:02:29 2001 @@ -0,0 +1,96 @@ +/* + * drivers/s390/char/controlchar.c + * Unified handling of special chars. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com> + * + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/tty.h> +#include <linux/interrupt.h> + +#include <linux/sysrq.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/delay.h> +#include <asm/cpcmd.h> +#include <asm/irq.h> + +#ifdef CONFIG_MAGIC_SYSRQ +static int ctrlchar_sysrq_key; +static struct tq_struct ctrlchar_tq; + +static void +ctrlchar_handle_sysrq(struct tty_struct *tty) { + handle_sysrq(ctrlchar_sysrq_key, NULL, NULL, tty); +} +#endif + +void ctrlchar_init(void) { +#ifdef CONFIG_MAGIC_SYSRQ + static int init_done = 0; + + if (init_done++) + return; + INIT_LIST_HEAD(&ctrlchar_tq.list); + ctrlchar_tq.sync = 0; + ctrlchar_tq.routine = ctrlchar_handle_sysrq; +#endif +} + +/** + * Check for special chars at start of input. + * + * @param buf Console input buffer. + * @param len Length of valid data in buffer. + * @param tty The tty struct for this console. + * @return NULL, if nothing matched, (char *)-1, if buffer contents + * should be ignored, otherwise pointer to char to be inserted. + */ +char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty) { + + static char ret; + + if ((len < 2) || (len > 3)) + return NULL; + /* hat is 0xb1 in codepage 037 (US etc.) and thus */ + /* converted to 0x5e in ascii ('^') */ + if ((buf[0] != '^') && (buf[0] != '\252')) + return NULL; + switch (buf[1]) { +#ifdef CONFIG_MAGIC_SYSRQ + case '-': + if (len == 3) { + ctrlchar_sysrq_key = buf[2]; + ctrlchar_tq.data = tty; + queue_task(&ctrlchar_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return (char *)-1; + } + break; +#endif + case 'c': + if (len == 2) { + ret = INTR_CHAR(tty); + return &ret; + } + break; + case 'd': + if (len == 2) { + ret = EOF_CHAR(tty); + return &ret; + } + break; + case 'z': + if (len == 2) { + ret = SUSP_CHAR(tty); + return &ret; + } + break; + } + return NULL; +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/ctrlchar.h linux/drivers/s390/char/ctrlchar.h --- v2.4.3/linux/drivers/s390/char/ctrlchar.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/ctrlchar.h Thu Apr 12 12:16:35 2001 @@ -0,0 +1,14 @@ +/* + * drivers/s390/char/controlchar.c + * Unified handling of special chars. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert <felfert@millenux.com> <elfert@de.ibm.com> + * + */ + +#include <linux/types.h> +#include <linux/tty.h> + +extern void ctrlchar_init(void); +extern char *ctrlchar_handle(const char *buf, int len, struct tty_struct *tty); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h --- v2.4.3/linux/drivers/s390/char/hwc.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/hwc.h Wed Apr 11 19:02:29 2001 @@ -39,6 +39,8 @@ #define HWC_BUSY 2 #define HWC_NOT_OPERATIONAL 3 +#define hwc_cmdw_t u32; + #define HWC_CMDW_READDATA 0x00770005 #define HWC_CMDW_WRITEDATA 0x00760005 @@ -207,9 +209,25 @@ 0x0000, 0x0000, sizeof (_hwcb_mask_t), - ET_OpCmd_Mask | ET_PMsgCmd_Mask, - ET_Msg_Mask + ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask, + ET_Msg_Mask | ET_PMsgCmd_Mask }; + +typedef struct { + _EBUF_HEADER + u8 validity_hwc_active_facility_mask:1; + u8 validity_hwc_receive_mask:1; + u8 validity_hwc_send_mask:1; + u8 validity_read_data_function_mask:1; + u16 _zeros:12; + u16 mask_length; + u64 hwc_active_facility_mask; + _hwcb_mask_t hwc_receive_mask; + _hwcb_mask_t hwc_send_mask; + u32 read_data_function_mask; +} __attribute__ ((packed)) + +statechangebuf_t; #define _GDS_VECTOR_HEADER u16 length; \ u16 gds_id; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_con.c linux/drivers/s390/char/hwc_con.c --- v2.4.3/linux/drivers/s390/char/hwc_con.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/hwc_con.c Wed Apr 11 19:02:29 2001 @@ -17,14 +17,13 @@ #include <linux/fs.h> #include <linux/init.h> +#include "ctrlchar.h" #include "hwc_rw.h" -extern void hwc_tty_init (void); - #ifdef CONFIG_HWC_CONSOLE #define hwc_console_major 4 -#define hwc_console_minor 0 +#define hwc_console_minor 64 #define hwc_console_name "console" void hwc_console_write (struct console *, const char *, unsigned int); @@ -84,17 +83,16 @@ hwc_console_init (void) { -#ifdef CONFIG_3215 +#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE) if (MACHINE_IS_VM) return; #endif if (MACHINE_IS_P390) return; + ctrlchar_init (); + if (hwc_init () == 0) { - - hwc_tty_init (); - #ifdef CONFIG_HWC_CONSOLE register_console (&hwc_console); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c --- v2.4.3/linux/drivers/s390/char/hwc_rw.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/hwc_rw.c Wed Apr 11 19:02:29 2001 @@ -30,9 +30,13 @@ #include <asm/s390_ext.h> #ifndef MIN -#define MIN(a,b) ((a<b) ? a : b) +#define MIN(a,b) (((a<b) ? a : b)) #endif +#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x])) + +#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c))) + #define HWC_RW_PRINT_HEADER "hwc low level driver: " #define USE_VM_DETECTION @@ -118,16 +122,16 @@ static unsigned char _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE))); -/* pedantic: long because we use set_bit on it --RR */ -typedef long kmem_pages_t; +typedef unsigned long kmem_pages_t; #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3) -#define HWC_TIMER_RUNS 1 -#define HWC_FLUSH 2 -#define HWC_INIT 4 -#define HWC_BROKEN 8 -#define HWC_INTERRUPT 16 +#define HWC_WTIMER_RUNS 1 +#define HWC_FLUSH 2 +#define HWC_INIT 4 +#define HWC_BROKEN 8 +#define HWC_INTERRUPT 16 +#define HWC_PTIMER_RUNS 32 static struct { @@ -169,6 +173,7 @@ unsigned char write_prio:1; unsigned char read_nonprio:1; unsigned char read_prio:1; + unsigned char read_statechange:1; unsigned char flags; @@ -177,6 +182,8 @@ spinlock_t lock; struct timer_list write_timer; + + struct timer_list poll_timer; } hwc_data = { { @@ -186,7 +193,7 @@ 0, 80, 1, - 50, + MAX_KMEM_PAGES, MAX_KMEM_PAGES, 0, @@ -214,6 +221,7 @@ 0, 0, 0, + 0, NULL }; @@ -345,9 +353,6 @@ memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t)); - if (!hwc_data.write_nonprio && hwc_data.write_prio) - hwcb->msgbuf.type = ET_PMsgCmd; - return 0; } @@ -647,25 +652,58 @@ return count; } +static int write_event_data_1 (void); + +static void +do_poll_hwc (unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave (&hwc_data.lock, flags); + + write_event_data_1 (); + + spin_unlock_irqrestore (&hwc_data.lock, flags); +} + +void +start_poll_hwc (void) +{ + init_timer (&hwc_data.poll_timer); + hwc_data.poll_timer.function = do_poll_hwc; + hwc_data.poll_timer.data = (unsigned long) NULL; + hwc_data.poll_timer.expires = jiffies + 2 * HZ; + add_timer (&hwc_data.poll_timer); + hwc_data.flags |= HWC_PTIMER_RUNS; +} + static int write_event_data_1 (void) { unsigned short int condition_code; int retval; + write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB; - if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio)) - return -EPERM; + if ((!hwc_data.write_prio) && + (!hwc_data.write_nonprio) && + hwc_data.read_statechange) + return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; retval = sane_write_hwcb (); if (retval < 0) - return retval; + return -EIO; if (!OUT_HWCB_MTO) return -ENODATA; + if (!hwc_data.write_nonprio && hwc_data.write_prio) + hwcb->msgbuf.type = ET_PMsgCmd; + else + hwcb->msgbuf.type = ET_Msg; + condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB); #ifdef DUMP_HWC_WRITE_ERROR @@ -688,6 +726,8 @@ case HWC_BUSY: retval = -EBUSY; break; + case HWC_NOT_OPERATIONAL: + start_poll_hwc (); default: retval = -EIO; } @@ -710,7 +750,7 @@ write_event_data_2 (void) { write_hwcb_t *hwcb; - int retval; + int retval = 0; #ifdef DUMP_HWC_WRITE_ERROR unsigned char *param; @@ -765,11 +805,22 @@ } #endif - if (hwcb->response_code == 0x0020) { + switch (hwcb->response_code) { + case 0x0020: retval = OUT_HWCB_CHAR; release_write_hwcb (); - } else { + break; + case 0x0040: + case 0x0340: + case 0x40F0: + if (!hwc_data.read_statechange) { + hwcb->response_code = 0; + start_poll_hwc (); + } + retval = -EIO; + break; + default: internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER @@ -782,6 +833,13 @@ retval = -EIO; } + if (retval == -EIO) { + + hwcb->control_mask[0] = 0; + hwcb->control_mask[1] = 0; + hwcb->control_mask[2] = 0; + hwcb->response_code = 0; + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -826,9 +884,9 @@ unsigned short count) { - if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) { + if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) { del_timer (&hwc_data.write_timer); - hwc_data.flags &= ~HWC_TIMER_RUNS; + hwc_data.flags &= ~HWC_WTIMER_RUNS; } hwc_data.obuf_start += count; @@ -937,7 +995,7 @@ if (obuf_cursor < obuf_columns) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor] - = 0x20; + = HWC_ASCEBC (' '); obuf_cursor++; } else break; @@ -955,7 +1013,7 @@ while (spaces) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor - spaces] - = 0x20; + = HWC_ASCEBC (' '); spaces--; } @@ -985,9 +1043,7 @@ if (isprint (ch)) hwc_data.obuf[hwc_data.obuf_start + obuf_cursor++] - = (MACHINE_IS_VM) ? - _ascebc[ch] : - _ascebc_500[ch]; + = HWC_ASCEBC (ch); } if (obuf_cursor > obuf_count) obuf_count = obuf_cursor; @@ -1006,11 +1062,10 @@ if (hwc_data.ioctls.final_nl > 0) { - if (hwc_data.flags & HWC_TIMER_RUNS) { + if (hwc_data.flags & HWC_WTIMER_RUNS) { - hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl * HZ / 10; + mod_timer (&hwc_data.write_timer, + jiffies + hwc_data.ioctls.final_nl * HZ / 10); } else { init_timer (&hwc_data.write_timer); @@ -1022,7 +1077,7 @@ jiffies + hwc_data.ioctls.final_nl * HZ / 10; add_timer (&hwc_data.write_timer); - hwc_data.flags |= HWC_TIMER_RUNS; + hwc_data.flags |= HWC_WTIMER_RUNS; } } else; @@ -1306,14 +1361,11 @@ if (hwc_data.ioctls.delim) count = seperate_cases (start, count); - if (MACHINE_IS_VM) - EBCASC (start, count); - else - EBCASC_500 (start, count); + HWC_EBCASC_STR (start, count); - if (hwc_data.ioctls.echo) { + if (hwc_data.ioctls.echo) do_hwc_write (0, start, count, IMMEDIATE_WRITE); - } + if (hwc_data.calls != NULL) if (hwc_data.calls->move_input != NULL) (hwc_data.calls->move_input) (start, count); @@ -1416,7 +1468,7 @@ return retval; } -inline static int +static int eval_evbuf (gds_vector_t * start, void *end) { gds_vector_t *vec; @@ -1434,6 +1486,128 @@ return retval; } +static inline int +eval_hwc_receive_mask (_hwcb_mask_t mask) +{ + + hwc_data.write_nonprio + = ((mask & ET_Msg_Mask) == ET_Msg_Mask); + + hwc_data.write_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + + if (hwc_data.write_prio || hwc_data.write_nonprio) { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can write messages\n"); + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not write messages\n"); + return -1; + } +} + +static inline int +eval_hwc_send_mask (_hwcb_mask_t mask) +{ + + hwc_data.read_statechange + = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask); + if (hwc_data.read_statechange) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read state change notifications\n"); + else + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read state change notifications\n"); + + hwc_data.read_nonprio + = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask); + if (hwc_data.read_nonprio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read commands\n"); + + hwc_data.read_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + if (hwc_data.read_prio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read priority commands\n"); + + if (hwc_data.read_prio || hwc_data.read_nonprio) { + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read commands from operator\n"); + return -1; + } +} + +static int +eval_statechangebuf (statechangebuf_t * scbuf) +{ + int retval = 0; + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "HWC state change detected\n"); + + if (scbuf->validity_hwc_active_facility_mask) { + + } + if (scbuf->validity_hwc_receive_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe50\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_receive_mask + (scbuf->hwc_receive_mask); + } + } + if (scbuf->validity_hwc_send_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe51\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_send_mask + (scbuf->hwc_send_mask); + } + } + if (scbuf->validity_read_data_function_mask) { + + } + return retval; +} + static int process_evbufs (void *start, void *end) { @@ -1466,17 +1640,17 @@ retval += eval_evbuf (evbuf_data, evbuf_end); break; case ET_StateChange: - - retval = -ENOSYS; + retval += eval_statechangebuf + ((statechangebuf_t *) evbuf); break; default: - printk ( - KERN_WARNING - HWC_RW_PRINT_HEADER - "unconditional read: " - "unknown event buffer found, " - "type 0x%x", - evbuf->type); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " + "unknown event buffer found, " + "type 0x%x", + evbuf->type); retval = -ENOSYS; } evbuf = (evbuf_t *) evbuf_end; @@ -1491,11 +1665,14 @@ read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; int retval; +#if 0 + if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio)) return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; +#endif memset (hwcb, 0x00, PAGE_SIZE); memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t)); @@ -1601,26 +1778,21 @@ internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: invalid function code - this " - "must not occur in a correct driver, please contact " - "author\n"); + "unconditional read: invalid function code\n"); return -EIO; case 0x70F0: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: invalid selection mask - this " - "must not occur in a correct driver, please contact " - "author\n"); + "unconditional read: invalid selection mask\n"); return -EIO; case 0x0040: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: HWC equipment check - don't " - "know how to handle this case\n"); + "unconditional read: HWC equipment check\n"); return -EIO; default: @@ -1677,27 +1849,7 @@ init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page; int retval = 0; - if (hwcb->hwc_receive_mask & ET_Msg_Mask) - hwc_data.write_nonprio = 1; - - if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask) - hwc_data.write_prio = 1; - - if (hwcb->hwc_send_mask & ET_OpCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of commands\n"); - hwc_data.read_nonprio = 1; - } - if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of priority commands\n"); - hwc_data.read_nonprio = 1; - } - if ((hwcb->response_code != 0x0020) || - (!hwc_data.write_nonprio) || - ((!hwc_data.read_nonprio) && (!hwc_data.read_prio))) + if (hwcb->response_code != 0x0020) { #ifdef DUMP_HWC_INIT_ERROR __asm__ ("LHI 1,0xe11\n\t" "LRA 2,0(%0)\n\t" @@ -1707,8 +1859,24 @@ : "a" (hwcb), "a" (&(hwcb->response_code)) : "1", "2", "3"); #else - retval = -EIO; + retval = -1; #endif + } else { + if (hwcb->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe52\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (hwcb) + : "1", "2"); +#endif + } else { + retval += eval_hwc_receive_mask + (hwcb->hwc_receive_mask); + retval += eval_hwc_send_mask (hwcb->hwc_send_mask); + } + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -1934,6 +2102,10 @@ } else { spin_lock (&hwc_data.lock); + if (hwc_data.flags & HWC_PTIMER_RUNS) { + del_timer (&hwc_data.poll_timer); + hwc_data.flags &= ~HWC_PTIMER_RUNS; + } if (!hwc_data.current_servc) { unconditional_read_1 (); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c --- v2.4.3/linux/drivers/s390/char/hwc_tty.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/hwc_tty.c Thu Apr 12 12:16:35 2001 @@ -9,12 +9,15 @@ * Thanks to Martin Schwidefsky. */ +#include <linux/config.h> #include <linux/major.h> #include <linux/termios.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/init.h> #include <asm/uaccess.h> @@ -184,29 +187,13 @@ struct tty_struct *tty = hwc_tty_data.tty; if (tty != NULL) { - - if (count == 2 && ( - /* hat is 0xb0 in codepage 037 (US etc.) and thus */ - /* converted to 0x5e in ascii ('^') */ - strncmp (buf, "^c", 2) == 0 || - /* hat is 0xb0 in several other codepages (German, */ - /* UK, ...) and thus converted to ascii octal 252 */ - strncmp (buf, "\0252c", 2) == 0)) { - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = INTR_CHAR (tty); - } else if (count == 2 && ( - strncmp (buf, "^d", 2) == 0 || - strncmp (buf, "\0252d", 2) == 0)) { - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = EOF_CHAR (tty); - } else if (count == 2 && ( - strncmp (buf, "^z", 2) == 0 || - strncmp (buf, "\0252z", 2) == 0)) { + char *cchar; + if ((cchar = ctrlchar_handle (buf, count, tty))) { + if (cchar == (char *) -1) + return; tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = SUSP_CHAR (tty); + *tty->flip.char_buf_ptr++ = *cchar; } else { memcpy (tty->flip.char_buf_ptr, buf, count); @@ -230,6 +217,13 @@ void hwc_tty_init (void) { +#ifdef CONFIG_3215 + if (MACHINE_IS_VM) + return; +#endif + if (MACHINE_IS_P390) + return; + memset (&hwc_tty_driver, 0, sizeof (struct tty_driver)); memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct)); hwc_tty_driver.magic = TTY_DRIVER_MAGIC; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape.c linux/drivers/s390/char/tape.c --- v2.4.3/linux/drivers/s390/char/tape.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape.c Wed Apr 11 19:02:28 2001 @@ -1,14 +1,13 @@ /*********************************************************************** * drivers/s390/char/tape.c - * tape device driver for S/390 tapes. + * tape device driver for S/390 and zSeries tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress... :-) *********************************************************************** */ @@ -34,9 +33,21 @@ #include <asm/s390dyn.h> #endif #include "tape.h" +#ifdef CONFIG_S390_TAPE_3490 #include "tape3490.h" +#endif +#ifdef CONFIG_S390_TAPE_3480 #include "tape3480.h" - +#endif +#ifdef CONFIG_S390_TAPE_BLOCK +#include "tapeblock.h" +#endif +#ifdef CONFIG_S390_TAPE_CHAR +#include "tapechar.h" +#endif +#ifdef CONFIG_PROC_FS +#include <linux/vmalloc.h> +#endif #define PRINTK_HEADER "T390:" /* state handling routines */ @@ -91,29 +102,118 @@ char* event_verbose[TE_SIZE]= { "TE_START", "TE_DONE", "TE_FAILED", "TE_ERROR", "TE_OTHER"}; -#ifdef CONFIG_PROC_FS /* don't waste space if unused */ -/* - * The proc filesystem: function to read and entry - */ -int -tape_read_procmem (char *buf, char **start, off_t offset, - int len, int unused) +/* our root devfs handle */ +#ifdef CONFIG_DEVFS_FS +devfs_handle_t tape_devfs_root_entry; + +inline void +tape_mkdevfsroots (tape_info_t* tape) +{ + char devno [5]; + sprintf (devno,"%04X",tape->devinfo.devno); + tape->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, tape); +} + +inline void +tape_rmdevfsroots (tape_info_t* tape) +{ + devfs_unregister (tape->devfs_dir); +} +#endif + +#ifdef CONFIG_PROC_FS +/* our proc tapedevices entry */ +static struct proc_dir_entry *tape_devices_entry; + +typedef struct { + char *data; + int len; +} tempinfo_t; + + +static int +tape_devices_open (struct inode *inode, struct file *file) +{ + int size=80; + tape_info_t* tape; + tempinfo_t* tempinfo; + char* data; + int pos=0; + tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL); + if (!tempinfo) + return -ENOMEM; + for (tape=first_tape_info;tape!=NULL;tape=tape->next) + size+=80; // FIXME: Guess better! + data=vmalloc(size); + if (!data) { + kfree (tempinfo); + return -ENOMEM; + } + pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n"); + for (tape=first_tape_info;tape!=NULL;tape=tape->next) { + pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",tape->rew_minor/2, + tape->devinfo.devno,tape->devinfo.sid_data.cu_type, + tape->devinfo.sid_data.cu_model,tape->devinfo.sid_data.dev_type, + tape->devinfo.sid_data.dev_model,((tapestate_get(tape) >= 0) && + (tapestate_get(tape) < TS_SIZE)) ? + state_verbose[tapestate_get (tape)] : "TS UNKNOWN"); + } + tempinfo->len=pos; + tempinfo->data=data; + file->private_data= (void*) tempinfo; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +static ssize_t +tape_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset) +{ + loff_t len; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + + if (*offset >= p_info->len) { + return 0; /* EOF */ + } else { + len = user_len<(p_info->len - *offset)?user_len:(p_info->len - *offset); + if (copy_to_user (user_buf, &(p_info->data[*offset]), len)) + return -EFAULT; + (*offset) += len; + return len; /* number of bytes "read" */ + } +} + +static int +tape_devices_release (struct inode *inode, struct file *file) { - tape_info_t *tape = first_tape_info; - len = sprintf (buf, "minor\tstate\n"); - do { - if (len >= PAGE_SIZE - 80) - len += sprintf (buf + len, "terminated...\n"); - len += sprintf (buf + len, - "%d\t%s\n", tape->rew_minor, - ((tapestate_get (tape) >= 0) && (tapestate_get (tape) < TS_SIZE)) ? - state_verbose[tapestate_get (tape)] : - "UNKNOWN STATE"); - } while ((tape = (tape_info_t *) (tape->next)) != NULL); - return len; + int rc = 0; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + if (p_info) { + if (p_info->data) + vfree (p_info->data); + kfree (p_info); + } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return rc; } -#endif /* CONFIG_PROC_FS */ +static struct file_operations tape_devices_file_ops = +{ + read:tape_devices_read, /* read */ + open:tape_devices_open, /* open */ + release:tape_devices_release, /* close */ +}; + +static struct inode_operations tape_devices_inode_ops = +{ +#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + default_file_ops:&tape_devices_file_ops /* file ops */ +#endif /* LINUX_IS_24 */ +}; +#endif /* CONFIG_PROC_FS */ /* SECTION: Managing wrappers for ccwcache */ @@ -258,7 +358,11 @@ int rc,tape_num,retries=0; s390_dev_info_t dinfo; tape_discipline_t* disc; +#ifdef CONFIG_DEVFS_FS + tape_frontend_t* frontend; +#endif long lockflags; + PRINT_WARN ("oper handler was called\n"); while ((tape!=NULL) && (tape->devinfo.irq!=irq)) tape=tape->next; if (tape!=NULL) { @@ -270,13 +374,19 @@ rc = get_dev_info_by_irq (irq, &dinfo); if (rc == -ENODEV) { retries++; - if (retries > 5) + rc = get_dev_info_by_irq (irq, &dinfo); + if (retries > 5) { + PRINT_WARN ("No device information for new dev. could be retrieved.\n"); return -ENODEV; + } } disc = first_discipline; while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type)) disc = (tape_discipline_t *) (disc->next); - + if (disc == NULL) + PRINT_WARN ("No matching discipline for cu_type %x found\n",dinfo.sid_data.cu_type); + if (rc == -ENODEV) + PRINT_WARN ("No device information for new dev. could be retrieved.\n"); if ((disc == NULL) || (rc == -ENODEV)) return -ENODEV; @@ -287,6 +397,7 @@ "tape info structure\n"); return -ENOBUFS; } + memset(tape,0,sizeof(tape_info_t)); tape->discipline = disc; disc->tape = tape; tape_num=0; @@ -306,6 +417,10 @@ kfree (tape); return -ENOBUFS; } +#ifdef CONFIG_DEVFS_FS + for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) + frontend->mkdevfstree(tape); +#endif s390irq_spin_lock_irqsave (irq,lockflags); if (first_tape_info == NULL) { first_tape_info = tape; @@ -324,41 +439,61 @@ tape_noper_handler ( int irq, int status ) { tape_info_t *ti=first_tape_info; tape_info_t *lastti; +#ifdef CONFIG_DEVFS_FS + tape_frontend_t *frontend; +#endif long lockflags; s390irq_spin_lock_irqsave(irq,lockflags); - while (ti!=NULL) { - if (ti->devinfo.irq==irq) { - tapestate_set(ti,TS_NOT_OPER); - if (tapestate_get(ti)!=TS_UNUSED) { - // device is in use! - PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor); - ti->rc=-ENXIO; - wake_up_interruptible(&ti->wq); - } else { - // device is unused! - if (ti==first_tape_info) { - first_tape_info=ti->next; - } else { - lastti=first_tape_info; - while (lastti->next!=ti) lastti=lastti->next; - lastti->next=ti->next; - } - kfree(ti); - } - s390irq_spin_unlock_irqrestore(irq,lockflags); - return; + while (ti!=NULL && ti->devinfo.irq!=irq) ti=ti->next; + if (ti==NULL) return; + if (tapestate_get(ti)!=TS_UNUSED) { + // device is in use! + PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor/2); + tapestate_set(ti,TS_NOT_OPER); + ti->rc=-ENODEV; + ti->wanna_wakeup=1; + switch (tapestate_get(ti)) { + case TS_REW_RELEASE_INIT: + tapestate_set(ti,TS_NOT_OPER); + wake_up (&ti->wq); + break; +#ifdef CONFIG_S390_TAPE_BLOCK + case TS_BLOCK_INIT: + tapestate_set(ti,TS_NOT_OPER); + schedule_tapeblock_exec_IO(ti); + break; +#endif + default: + tapestate_set(ti,TS_NOT_OPER); + wake_up_interruptible (&ti->wq); + } + } else { + // device is unused! + PRINT_WARN ("Tape #%d was detached.\n",ti->blk_minor/2); + if (ti==first_tape_info) { + first_tape_info=ti->next; + } else { + lastti=first_tape_info; + while (lastti->next!=ti) lastti=lastti->next; + lastti->next=ti->next; } - ti=ti->next; +#ifdef CONFIG_DEVFS_FS + for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) + frontend->rmdevfstree(ti); + tape_rmdevfsroots(ti); +#endif + kfree(ti); } s390irq_spin_unlock_irqrestore(irq,lockflags); - PRINT_WARN ("Tape not found for irq %d. Device is detached.",irq); + return; } void tape_dump_sense (devstat_t * stat) { - int sl, sct; + int sl; +#if 0 PRINT_WARN ("------------I/O resulted in unit check:-----------\n"); for (sl = 0; sl < 4; sl++) { PRINT_WARN ("Sense:"); @@ -388,6 +523,7 @@ stat->ii.sense.data[26], stat->ii.sense.data[27], stat->ii.sense.data[28], stat->ii.sense.data[29], stat->ii.sense.data[30], stat->ii.sense.data[31]); +#endif #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"SENSE:"); for (sl=0;sl<31;sl++) { @@ -413,6 +549,9 @@ ti->rew_minor = minor; ti->nor_minor = minor + 1; ti->blk_minor = minor; +#ifdef CONFIG_DEVFS_FS + tape_mkdevfsroots(ti); +#endif /* Register IRQ */ #ifdef CONFIG_S390_TAPE_DYNAMIC rc = s390_request_irq_special (irq, tape_irq, tape_noper_handler,0, "tape", &(ti->devstat)); @@ -424,7 +563,7 @@ if (rc) { PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc); } else - PRINT_WARN ("Register irq %d for using with discipline %x\n", irq, ti->discipline->cu_type); + PRINT_WARN ("Register irq %d for using with discipline %x dev #%d\n", irq, ti->discipline->cu_type,ti->blk_minor/2); init_waitqueue_head (&ti->wq); ti->kernbuf = ti->userbuf = ti->discdata = NULL; tapestate_set (ti, TS_UNUSED); @@ -460,7 +599,7 @@ #endif /* TAPE_DEBUG */ /* print banner */ - PRINT_WARN ("IBM S/390 Tape Device Driver (ALPHA).\n"); + PRINT_WARN ("IBM S/390 Tape Device Driver (BETA).\n"); PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000\n"); opt_char=opt_block=opt_3480=opt_3490="not present"; #ifdef CONFIG_S390_TAPE_CHAR @@ -496,6 +635,9 @@ ((tape_discipline_t*) (first_discipline->next))->next=NULL; } #endif +#ifdef CONFIG_DEVFS_FS + tape_devfs_root_entry=devfs_mk_dir (NULL, "tape", NULL); +#endif CONFIG_DEVFS_FS #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"dev detect"); @@ -558,17 +700,40 @@ /* Allocate local buffer for the ccwcache */ tape_init_emergency_req (); - -#if 0 // need to register s.th. for proc? FIXME! - if (proc_register_dynamic (&proc_root, &proc_root_tape)) - PRINT_INFO (KERN_ERR "tape: registering " - "/proc/tape failed\n"); +#ifdef CONFIG_PROC_FS +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + tape_devices_entry = create_proc_entry ("tapedevices", + S_IFREG | S_IRUGO | S_IWUSR, + &proc_root); + tape_devices_entry->proc_fops = &tape_devices_file_ops; + tape_devices_entry->proc_iops = &tape_devices_inode_ops; +#else + tape_devices_entry = (struct proc_dir_entry *) kmalloc + (sizeof (struct proc_dir_entry), GFP_ATOMIC); + if (tape_devices_entry) { + memset (tape_devices_entry, 0, sizeof (struct proc_dir_entry)); + tape_devices_entry->name = "tapedevices"; + tape_devices_entry->namelen = strlen ("tapedevices"); + tape_devices_entry->low_ino = 0; + tape_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR); + tape_devices_entry->nlink = 1; + tape_devices_entry->uid = 0; + tape_devices_entry->gid = 0; + tape_devices_entry->size = 0; + tape_devices_entry->get_info = NULL; + tape_devices_entry->ops = &tape_devices_inode_ops; + proc_register (&proc_root, tape_devices_entry); + } #endif +#endif /* CONFIG_PROC_FS */ return 0; } #ifdef MODULE +MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte (cotte@de.ibm.com)"); +MODULE_DESCRIPTION("Linux for S/390 channel attached tape device driver"); + int init_module (void) { @@ -578,7 +743,7 @@ #ifdef CONFIG_S390_TAPE_BLOCK tapeblock_init (); #endif - return 0; + return 0; } void @@ -591,10 +756,6 @@ debug_text_event (tape_debug_area,6,"cleaup mod"); #endif /* TAPE_DEBUG */ -#if 0 /* FIXME: Do we need to register s.th? */ - proc_unregister (&proc_root, proc_root_tape.low_ino); -#endif - tape = first_tape_info; while (tape != NULL) { temp = tape; @@ -607,13 +768,25 @@ free_irq (temp->devinfo.irq, &(temp->devstat)); if (temp->discdata) kfree (temp->discdata); if (temp->kernbuf) kfree (temp->kernbuf); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) // COMPAT:FIXME -#else - kfree (temp->wq); -#endif if (temp->cqr) tape_free_request(temp->cqr); +#ifdef CONFIG_DEVFS_FS + for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) + frontend->rmdevfstree(temp); + tape_rmdevfsroots(temp); +#endif kfree (temp); } +#ifdef CONFIG_DEVFS_FS + devfs_unregister (tape_devfs_root_entry); +#endif CONFIG_DEVFS_FS +#ifdef CONFIG_PROC_FS +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + remove_proc_entry ("devices", &proc_root); +#else + proc_unregister (&proc_root, tape_devices_entry->low_ino); + kfree (tape_devices_entry); +#endif /* LINUX_IS_24 */ +#endif #ifdef CONFIG_S390_TAPE_CHAR tapechar_uninit(); #endif @@ -689,18 +862,22 @@ state_verbose[tapestate_get (tape)] : "TS UNKNOWN"); #endif /* TAPE_DEBUG */ - if ((event >= 0) && - (event < TE_SIZE) && - (tapestate_get (tape) >= 0) && - (tapestate_get (tape) < TS_SIZE) && - ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL)) + if (event == TE_ERROR) { + tape->discipline->error_recovery(tape); + } else { + if ((event >= 0) && + (event < TE_SIZE) && + (tapestate_get (tape) >= 0) && + (tapestate_get (tape) < TS_SIZE) && + ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL)) ((*(tape->discipline->event_table))[tapestate_get (tape)][event]) (tape); - else { + else { #ifdef TAPE_DEBUG debug_text_exception (tape_debug_area,3,"TE UNEXPEC"); #endif /* TAPE_DEBUG */ tape->discipline->default_handler (tape); - } + } + } } /* diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape.h linux/drivers/s390/char/tape.h --- v2.4.3/linux/drivers/s390/char/tape.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape.h Wed Apr 11 19:02:28 2001 @@ -1,15 +1,13 @@ - /*************************************************************************** * * drivers/s390/char/tape.h * tape device driver for 3480/3490E tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -71,10 +69,14 @@ typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* tape); typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* tape); typedef void (*tape_setup_assist_t) (struct _tape_info_t*); +#ifdef CONFIG_DEVFS_FS +typedef void (*tape_devfs_handler_t) (struct _tape_info_t*); +#endif typedef tape_event_handler_t tape_event_table_t[TS_SIZE][TE_SIZE]; typedef struct _tape_discipline_t { unsigned int cu_type; tape_setup_assist_t setup_assist; + tape_event_handler_t error_recovery; tape_reqgen_t bread; tape_freeblock_t free_bread; tape_rwblock_t write_block; @@ -115,6 +117,10 @@ typedef struct _tape_frontend_t { tape_setup_assist_t device_setup; +#ifdef CONFIG_DEVFS_FS + tape_devfs_handler_t mkdevfstree; + tape_devfs_handler_t rmdevfstree; +#endif void* next; } tape_frontend_t __attribute__ ((aligned(8))); @@ -142,6 +148,14 @@ ccw_req_t* cqr; atomic_t bh_scheduled; struct tq_struct bh_tq; +#ifdef CONFIG_DEVFS_FS + devfs_handle_t devfs_dir; /* devfs handle for tape/DEVNO directory */ + devfs_handle_t devfs_char_dir; /* devfs handle for tape/DEVNO/char directory */ + devfs_handle_t devfs_block_dir; /* devfs handle for tape/DEVNO/block directory */ + devfs_handle_t devfs_nonrewinding; /* devfs handle for tape/DEVNO/char/nonrewinding device */ + devfs_handle_t devfs_rewinding; /* devfs handle for tape/DEVNO/char/rewinding device */ + devfs_handle_t devfs_disc; /* devfs handle for tape/DEVNO/block/disc device */ +#endif void* discdata; void* kernbuf; void* userbuf; @@ -167,6 +181,7 @@ /* functions for handling the status of a device */ inline void tapestate_set (tape_info_t * tape, int newstate); inline int tapestate_get (tape_info_t * tape); +void tapestate_event (tape_info_t * tape, int event); extern char* state_verbose[TS_SIZE]; extern char* event_verbose[TE_SIZE]; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3480.c linux/drivers/s390/char/tape3480.c --- v2.4.3/linux/drivers/s390/char/tape3480.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape3480.c Wed Apr 11 19:02:28 2001 @@ -3,12 +3,11 @@ * drivers/s390/char/tape3480.c * tape device discipline for 3480 tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> - * - * UNDER CONSTRUCTION: Work in progress...:-) + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * **************************************************************************** */ @@ -25,31 +24,31 @@ tape_event_handler_t tape3480_event_handler_table[TS_SIZE][TE_SIZE] = { /* {START , DONE, FAILED, ERROR, OTHER } */ - {NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL}, /* TS_UNUSED */ - {NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL}, /* TS_IDLE */ + {NULL, tape34xx_unused_done, NULL, NULL, NULL}, /* TS_UNUSED */ + {NULL, tape34xx_idle_done, NULL, NULL, NULL}, /* TS_IDLE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_DONE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_FAILED */ - {NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL}, /* TS_BLOCK_INIT */ + {NULL, tape34xx_block_done, NULL, NULL, NULL}, /* TS_BLOCK_INIT */ {NULL, tape34xx_bsb_init_done, NULL, NULL, NULL}, /* TS_BSB_INIT */ {NULL, tape34xx_bsf_init_done, NULL, NULL, NULL}, /* TS_BSF_INIT */ {NULL, tape34xx_dse_init_done, NULL, NULL, NULL}, /* TS_DSE_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_EGA_INIT */ {NULL, tape34xx_fsb_init_done, NULL, NULL, NULL}, /* TS_FSB_INIT */ - {NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL}, /* TS_FSF_INIT */ + {NULL, tape34xx_fsf_init_done, NULL, NULL, NULL}, /* TS_FSF_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_LDI_INIT */ - {NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL}, /* TS_LBL_INIT */ + {NULL, tape34xx_lbl_init_done, NULL, NULL, NULL}, /* TS_LBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_MSE_INIT */ {NULL, tape34xx_nop_init_done, NULL, NULL, NULL}, /* TS_NOP_INIT */ - {NULL, NULL, NULL, NULL, NULL}, /* TS_RBA_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RBA_INIT */ {NULL, tape34xx_rbi_init_done, NULL, NULL, NULL}, /* TS_RBI_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBU_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RDC_INIT */ - {NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL}, /* TS_RFO_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RFO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RSD_INIT */ - {NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL}, /* TS_REW_INIT */ - {NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL}, /* TS_REW_RELEASE_IMIT */ - {NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL}, /* TS_RUN_INIT */ + {NULL, tape34xx_rew_init_done, NULL, NULL, NULL}, /* TS_REW_INIT */ + {NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL}, /* TS_REW_RELEASE_IMIT */ + {NULL, tape34xx_run_init_done, NULL, NULL, NULL}, /* TS_RUN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SEN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SID_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SNP_INIT */ @@ -59,14 +58,16 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_SYN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_TIO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_UNA_INIT */ - {NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL}, /* TS_WRI_INIT */ - {NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL}, /* TS_WTM_INIT */ + {NULL, tape34xx_wri_init_done, NULL, NULL, NULL}, /* TS_WRI_INIT */ + {NULL, tape34xx_wtm_init_done, NULL, NULL, NULL}, /* TS_WTM_INIT */ {NULL, NULL, NULL, NULL, NULL}}; /* TS_NOT_OPER */ devreg_t tape3480_devreg = { - ci : { hc: { ctype: 0x3480, dtype: 0x3480 } }, - flag: DEVREG_MATCH_CU_TYPE, - oper_func: tape_oper_handler + ci: + {hc: + {ctype:0x3480}}, + flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS, + oper_func:tape_oper_handler }; @@ -101,6 +102,7 @@ } disc->cu_type = 0x3480; disc->setup_assist = tape3480_setup_assist; + disc->error_recovery = tape34xx_error_recovery; disc->write_block = tape34xx_write_block; disc->free_write_block = tape34xx_free_write_block; disc->read_block = tape34xx_read_block; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3480.h linux/drivers/s390/char/tape3480.h --- v2.4.3/linux/drivers/s390/char/tape3480.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape3480.h Wed Apr 11 19:02:28 2001 @@ -1,15 +1,13 @@ - /*************************************************************************** * * drivers/s390/char/tape3480.h * tape device discipline for 3480 tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3490.c linux/drivers/s390/char/tape3490.c --- v2.4.3/linux/drivers/s390/char/tape3490.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape3490.c Wed Apr 11 19:02:28 2001 @@ -3,12 +3,11 @@ * drivers/s390/char/tape3490.c * tape device discipline for 3490E tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -25,31 +24,31 @@ tape_event_handler_t tape3490_event_handler_table[TS_SIZE][TE_SIZE] = { /* {START , DONE, FAILED, ERROR, OTHER } */ - {NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL}, /* TS_UNUSED */ - {NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL}, /* TS_IDLE */ + {NULL, tape34xx_unused_done, NULL, NULL, NULL}, /* TS_UNUSED */ + {NULL, tape34xx_idle_done, NULL, NULL, NULL}, /* TS_IDLE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_DONE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_FAILED */ - {NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL}, /* TS_BLOCK_INIT */ + {NULL, tape34xx_block_done, NULL, NULL, NULL}, /* TS_BLOCK_INIT */ {NULL, tape34xx_bsb_init_done, NULL, NULL, NULL}, /* TS_BSB_INIT */ {NULL, tape34xx_bsf_init_done, NULL, NULL, NULL}, /* TS_BSF_INIT */ {NULL, tape34xx_dse_init_done, NULL, NULL, NULL}, /* TS_DSE_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_EGA_INIT */ {NULL, tape34xx_fsb_init_done, NULL, NULL, NULL}, /* TS_FSB_INIT */ - {NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL}, /* TS_FSF_INIT */ + {NULL, tape34xx_fsf_init_done, NULL, NULL, NULL}, /* TS_FSF_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_LDI_INIT */ - {NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL}, /* TS_LBL_INIT */ + {NULL, tape34xx_lbl_init_done, NULL, NULL, NULL}, /* TS_LBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_MSE_INIT */ {NULL, tape34xx_nop_init_done, NULL, NULL, NULL}, /* TS_NOP_INIT */ - {NULL, NULL, NULL, NULL, NULL}, /* TS_RBA_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RBA_INIT */ {NULL, tape34xx_rbi_init_done, NULL, NULL, NULL}, /* TS_RBI_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBU_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RDC_INIT */ - {NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL}, /* TS_RFO_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RFO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RSD_INIT */ - {NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL}, /* TS_REW_INIT */ - {NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL}, /* TS_REW_RELEASE_IMIT */ - {NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL}, /* TS_RUN_INIT */ + {NULL, tape34xx_rew_init_done, NULL, NULL, NULL}, /* TS_REW_INIT */ + {NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL}, /* TS_REW_RELEASE_IMIT */ + {NULL, tape34xx_run_init_done, NULL, NULL, NULL}, /* TS_RUN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SEN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SID_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SNP_INIT */ @@ -59,14 +58,16 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_SYN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_TIO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_UNA_INIT */ - {NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL}, /* TS_WRI_INIT */ - {NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL}, /* TS_WTM_INIT */ + {NULL, tape34xx_wri_init_done, NULL, NULL, NULL}, /* TS_WRI_INIT */ + {NULL, tape34xx_wtm_init_done, NULL, NULL, NULL}, /* TS_WTM_INIT */ {NULL, NULL, NULL, NULL, NULL}}; /* TS_NOT_OPER */ devreg_t tape3490_devreg = { - ci : { hc: { ctype: 0x3490, dtype: 0x3490 } }, - flag: DEVREG_MATCH_CU_TYPE, - oper_func: tape_oper_handler + ci: + {hc: + {ctype:0x3490}}, + flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS, + oper_func:tape_oper_handler }; void @@ -100,6 +101,7 @@ } disc->cu_type = 0x3490; disc->setup_assist = tape3490_setup_assist; + disc->error_recovery = tape34xx_error_recovery; disc->write_block = tape34xx_write_block; disc->free_write_block = tape34xx_free_write_block; disc->read_block = tape34xx_read_block; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape3490.h linux/drivers/s390/char/tape3490.h --- v2.4.3/linux/drivers/s390/char/tape3490.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape3490.h Wed Apr 11 19:02:28 2001 @@ -4,12 +4,11 @@ * drivers/s390/char/tape3490.h * tape device discipline for 3490E tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c --- v2.4.3/linux/drivers/s390/char/tape34xx.c Fri Mar 2 11:12:07 2001 +++ linux/drivers/s390/char/tape34xx.c Wed Apr 11 19:02:28 2001 @@ -3,12 +3,11 @@ * drivers/s390/char/tape34xx.c * common tape device discipline for 34xx tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -36,19 +35,19 @@ tape_event_handler_t tape34xx_event_handler_table[TS_SIZE][TE_SIZE] = { /* {START , DONE, FAILED, ERROR, OTHER } */ - {NULL, tape34xx_unused_done, NULL, tape34xx_unused_error, NULL}, /* TS_UNUSED */ - {NULL, tape34xx_idle_done, NULL, tape34xx_idle_error, NULL}, /* TS_IDLE */ + {NULL, tape34xx_unused_done, NULL, NULL, NULL}, /* TS_UNUSED */ + {NULL, tape34xx_idle_done, NULL, NULL, NULL}, /* TS_IDLE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_DONE */ {NULL, NULL, NULL, NULL, NULL}, /* TS_FAILED */ - {NULL, tape34xx_block_done, NULL, tape34xx_block_error, NULL}, /* TS_BLOCK_INIT */ + {NULL, tape34xx_block_done, NULL, NULL, NULL}, /* TS_BLOCK_INIT */ {NULL, tape34xx_bsb_init_done, NULL, NULL, NULL}, /* TS_BSB_INIT */ {NULL, tape34xx_bsf_init_done, NULL, NULL, NULL}, /* TS_BSF_INIT */ {NULL, tape34xx_dse_init_done, NULL, NULL, NULL}, /* TS_DSE_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_EGA_INIT */ {NULL, tape34xx_fsb_init_done, NULL, NULL, NULL}, /* TS_FSB_INIT */ - {NULL, tape34xx_fsf_init_done, NULL, tape34xx_fsf_init_error, NULL}, /* TS_FSF_INIT */ + {NULL, tape34xx_fsf_init_done, NULL, NULL, NULL}, /* TS_FSF_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_LDI_INIT */ - {NULL, tape34xx_lbl_init_done, NULL, tape34xx_lbl_init_error, NULL}, /* TS_LBL_INIT */ + {NULL, tape34xx_lbl_init_done, NULL, NULL, NULL}, /* TS_LBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_MSE_INIT */ {NULL, tape34xx_nop_init_done, NULL, NULL, NULL}, /* TS_NOP_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBA_INIT */ @@ -56,11 +55,11 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBU_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RBL_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RDC_INIT */ - {NULL, tape34xx_rfo_init_done, NULL, tape34xx_rfo_init_error, NULL}, /* TS_RFO_INIT */ + {NULL, tape34xx_rfo_init_done, NULL, NULL, NULL}, /* TS_RFO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_RSD_INIT */ - {NULL, tape34xx_rew_init_done, NULL, tape34xx_rew_init_error, NULL}, /* TS_REW_INIT */ - {NULL, tape34xx_rew_release_init_done, NULL, tape34xx_rew_release_init_error, NULL}, /* TS_REW_RELEASE_IMIT */ - {NULL, tape34xx_run_init_done, NULL, tape34xx_run_init_error, NULL}, /* TS_RUN_INIT */ + {NULL, tape34xx_rew_init_done, NULL, NULL, NULL}, /* TS_REW_INIT */ + {NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL}, /* TS_REW_RELEASE_IMIT */ + {NULL, tape34xx_run_init_done, NULL, NULL, NULL}, /* TS_RUN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SEN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SID_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_SNP_INIT */ @@ -70,8 +69,8 @@ {NULL, NULL, NULL, NULL, NULL}, /* TS_SYN_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_TIO_INIT */ {NULL, NULL, NULL, NULL, NULL}, /* TS_UNA_INIT */ - {NULL, tape34xx_wri_init_done, NULL, tape34xx_wri_init_error, NULL}, /* TS_WRI_INIT */ - {NULL, tape34xx_wtm_init_done, NULL, tape34xx_wtm_init_error, NULL}, /* TS_WTM_INIT */ + {NULL, tape34xx_wri_init_done, NULL, NULL, NULL}, /* TS_WRI_INIT */ + {NULL, tape34xx_wtm_init_done, NULL, NULL, NULL}, /* TS_WTM_INIT */ {NULL, NULL, NULL, NULL, NULL}}; /* TS_NOT_OPER */ @@ -205,6 +204,59 @@ #endif /* TAPE_DEBUG */ return cqr; } +ccw_req_t * +tape34xx_read_opposite (tape_info_t * tape,int novalue) +{ + ccw_req_t *cqr; + ccw1_t *ccw; + size_t count; + // first, retrieve the count from the old cqr. + cqr = tape->cqr; + ccw = cqr->cpaddr; + ccw++; + count=ccw->count; + // free old cqr. + clear_normalized_cda (ccw); + tape_free_request (cqr); + // build new cqr + cqr = tape_alloc_ccw_req (tape, 3, 0); + if (!cqr) { +#ifdef TAPE_DEBUG + debug_text_exception (tape_debug_area,6,"xrop nomem"); +#endif /* TAPE_DEBUG */ + return NULL; + } + ccw = cqr->cpaddr; + ccw->cmd_code = MODE_SET_DB; + ccw->flags = CCW_FLAG_CC; + ccw->count = 1; + set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte))); + ccw++; + + ccw->cmd_code = READ_BACKWARD; + ccw->flags = CCW_FLAG_CC; + ccw->count = count; + set_normalized_cda (ccw, (unsigned long) tape->kernbuf); + if ((ccw->cda) == 0) { + tape_free_request (cqr); + return NULL; + } + ccw++; + ccw->cmd_code = FORSPACEBLOCK; + ccw->flags = CCW_FLAG_CC; + ccw->count = 1; + ccw->cda = (unsigned long)ccw; + ccw++; + ccw->cmd_code = NOP; + ccw->flags = 0; + ccw->count = 1; + ccw->cda = (unsigned long)ccw; + tapestate_set (tape, TS_RBA_INIT); +#ifdef TAPE_DEBUG + debug_text_event (tape_debug_area,6,"xrop ccwg"); +#endif /* TAPE_DEBUG */ + return cqr; +} void tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape) @@ -233,7 +285,6 @@ #endif /* TAPE_DEBUG */ } - /* * The IOCTL interface is implemented in the following section, * excepted the MTRESET, MTSETBLK which are handled by tapechar.c @@ -1329,7 +1380,7 @@ else bhct++; } - if ((data = kmalloc (4 * sizeof (__u8), GFP_KERNEL)) == NULL) { + if ((data = kmalloc (4 * sizeof (__u8), GFP_ATOMIC)) == NULL) { #ifdef TAPE_DEBUG debug_text_exception (tape_debug_area,3,"xBREDnomem"); #endif /* TAPE_DEBUG */ @@ -1395,9 +1446,8 @@ size, blksize_size[tapeblock_major][tape->blk_minor], req->nr_sectors); - - tape_free_request (cqr); kfree(data); + tape_free_request (cqr); return NULL; } } @@ -1506,17 +1556,6 @@ } } -void -tape34xx_unused_error (tape_info_t * tape) -{ -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"unsol.irq!"); - debug_text_event (tape_debug_area,3,"unit chk!"); - debug_int_exception (tape_debug_area,3,tape->devinfo.irq); -#endif /* TAPE_DEBUG */ - PRINT_WARN ("Unsolicited IRQ (Unit Check) caught in unused state.\n"); - tape_dump_sense (&tape->devstat); -} void tape34xx_idle_done (tape_info_t * tape) @@ -1531,18 +1570,6 @@ } void -tape34xx_idle_error (tape_info_t * tape) -{ -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"unsol.irq!"); - debug_text_event (tape_debug_area,3,"unit chk!"); - debug_int_exception (tape_debug_area,3,tape->devinfo.irq); -#endif /* TAPE_DEBUG */ - PRINT_WARN ("Unsolicited IRQ (Unit Check) caught in idle state.\n"); - tape_dump_sense (&tape->devstat); -} - -void tape34xx_block_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1553,16 +1580,6 @@ } void -tape34xx_block_error (tape_info_t * tape) -{ -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"x:xREQfail"); -#endif /* TAPE_DEBUG */ - tapestate_set(tape,TS_FAILED); - schedule_tapeblock_exec_IO(tape); -} - -void tape34xx_bsf_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1599,27 +1616,6 @@ } void -tape34xx_fsf_init_error (tape_info_t * tape) -{ - if (((tape->devstat.ii.sense.data[0] == 0x08) || // sense.data[0]=08 -> first time - (tape->devstat.ii.sense.data[0] == 0x10) || // an alternate one... - (tape->devstat.ii.sense.data[0] == 0x12)) && // sense.data[1]=12 -> repeated message - (tape->devstat.ii.sense.data[1] == 0x40)) { - // end of recorded area! -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"fsf fail"); - debug_text_exception (tape_debug_area,3,"eoRecArea"); -#endif /* TAPE_DEBUG */ - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - } else { - tape34xx_unexpect_uchk_handler (tape); - } -} - -void tape34xx_fsb_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1657,29 +1653,6 @@ } void -tape34xx_lbl_init_error (tape_info_t * tape) -{ - if (((tape->devstat.ii.sense.data[0] == 0x00) || // sense.data[0]=00 -> first time - (tape->devstat.ii.sense.data[0] == 0x08) || // an alternate one... - (tape->devstat.ii.sense.data[0] == 0x10) || // alternate, too - (tape->devstat.ii.sense.data[0] == 0x12)) && // sense.data[1]=12 -> repeated message - ((tape->devstat.ii.sense.data[1] == 0x40) || - (tape->devstat.ii.sense.data[1] == 0xc0))) { - // block not found! -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"lbl fail"); - debug_text_exception (tape_debug_area,3,"blk nfound"); -#endif /* TAPE_DEBUG */ - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - } else { - tape34xx_unexpect_uchk_handler (tape); - } -} - -void tape34xx_nop_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1699,11 +1672,8 @@ #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"rfo done"); #endif - //BH: use irqsave - //s390irq_spin_lock(tape->devinfo.irq); tapestate_set (tape, TS_DONE); tape->rc = 0; - //s390irq_spin_unlock(tape->devinfo.irq); tape->wanna_wakeup=1; wake_up_interruptible (&tape->wq); } @@ -1729,50 +1699,6 @@ } void -tape34xx_rfo_init_error (tape_info_t * tape) -{ - if (((tape->devstat.ii.sense.data[0] == 0x08) || // sense.data[0]=08 -> first time - (tape->devstat.ii.sense.data[0] == 0x10) || // an alternate one... - (tape->devstat.ii.sense.data[0] == 0x12)) && // sense.data[1]=12 -> repeated message - (tape->devstat.ii.sense.data[1] == 0x40)) { - // end of recorded area! -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rfo fail"); - debug_text_exception (tape_debug_area,3,"eoRecArea"); -#endif /* TAPE_DEBUG */ - tape->rc = 0; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - } else { - switch (tape->devstat.ii.sense.data[3]) { - case 0x48: -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rfo fail"); - debug_text_exception (tape_debug_area,3,"recov x48"); -#endif /* TAPE_DEBUG */ - //s390irq_spin_lock(tape->devinfo.irq); - do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) (tape->cqr), 0x00, tape->cqr->options); - //s390irq_spin_unlock(tape->devinfo.irq); - break; - case 0x2c: - PRINT_ERR ("TAPE: Permanent Unit Check. Please check your hardware!"); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rfo fail"); - debug_text_exception (tape_debug_area,3,"Perm UCK"); -#endif - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; - default: - tape34xx_unexpect_uchk_handler (tape); - } - } -} - -void tape34xx_rew_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1788,44 +1714,6 @@ } void -tape34xx_rew_release_init_error (tape_info_t * tape) -{ - if ((tape->devstat.ii.sense.data[0] == 0x40) && - (tape->devstat.ii.sense.data[1] == 0x40) && - (tape->devstat.ii.sense.data[3] == 0x43)) { - // no tape in the drive - PRINT_INFO ("Drive %d not ready. No volume loaded.\n", tape->rew_minor / 2); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rewR fail"); - debug_text_exception (tape_debug_area,3,"no medium"); -#endif - tapestate_set (tape, TS_FAILED); - tape->rc = -ENOMEDIUM; - tape->wanna_wakeup=1; - wake_up (&tape->wq); - } else { - PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n"); - PRINT_ERR ("TAPE34XX: Please send the following 20 lines of output to cotte@de.ibm.com\n"); - PRINT_ERR ("TAPE34XX: Current state is: %s", - (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ? - state_verbose[tapestate_get (tape)] : "->UNKNOWN STATE<-")); - tapestate_set (tape, TS_FAILED); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"rewR unexp"); - debug_text_event (tape_debug_area,3,"state:"); - debug_text_event (tape_debug_area,3,((tapestate_get (tape) < TS_SIZE) && - (tapestate_get (tape) >= 0)) ? - state_verbose[tapestate_get (tape)] : - "TS UNKNOWN"); -#endif /* TAPE_DEBUG */ - tape_dump_sense (&tape->devstat); - tape->rc = -EIO; - tape->wanna_wakeup=1; - wake_up (&tape->wq); - } -} - -void tape34xx_rew_release_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1839,12 +1727,6 @@ } void -tape34xx_rew_init_error (tape_info_t * tape) -{ - tape34xx_unexpect_uchk_handler (tape); -} - -void tape34xx_run_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1857,27 +1739,6 @@ } void -tape34xx_run_init_error (tape_info_t * tape) -{ - - switch (tape->devstat.ii.sense.data[3]) { - case 0x52: - // This error is fine for rewind and unload - // It reports that no volume is loaded... -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,6,"run done"); -#endif /* TAPE_DEBUG */ - tapestate_set (tape, TS_DONE); - tape->rc = 0; - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; - default: - tape34xx_unexpect_uchk_handler (tape); - } -} - -void tape34xx_wri_init_done (tape_info_t * tape) { #ifdef TAPE_DEBUG @@ -1893,72 +1754,632 @@ } void -tape34xx_wri_init_error (tape_info_t * tape) +tape34xx_wtm_init_done (tape_info_t * tape) { - if ((tape->devstat.ii.sense.data[0]==0x80)&&(tape->devstat.ii.sense.data[1]==0x4a)) { - // tape is write protected #ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"writProte"); -#endif /* TAPE_DEBUG */ - tape->rc = -EACCES; - tapestate_set (tape, TS_FAILED); + debug_text_event (tape_debug_area,3,"wtm done"); +#endif + tapestate_set (tape, TS_DONE); + tape->rc = 0; tape->wanna_wakeup=1; wake_up_interruptible (&tape->wq); - } else { - switch (tape->devstat.ii.sense.data[3]) { - case 0x48: -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"recov x48"); -#endif /* TAPE_DEBUG */ - //s390irq_spin_lock(tape->devinfo.irq); - do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) (tape->cqr), 0x00, tape->cqr->options); - //s390irq_spin_unlock(tape->devinfo.irq); - break; - case 0x2c: - PRINT_ERR ("TAPE: Permanent Unit Check. Please check your hardware!\n"); -#ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"Perm UCK"); -#endif - tape->rc = -EIO; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; - case 0x38: //end of tape -#ifdef TAPE_DEBUG - PRINT_WARN ("TAPE: End of Tape reached.\n"); - debug_text_event (tape_debug_area,3,"wri fail"); - debug_text_exception (tape_debug_area,3,"EOT!"); -#endif - tape->rc = tape->devstat.rescnt; - tapestate_set (tape, TS_FAILED); - tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); - break; +} + +/* This function analyses the tape's sense-data in case of a unit-check. If possible, + it tries to recover from the error. Else the user is informed about the problem. */ +void +tape34xx_error_recovery (tape_info_t* tape) +{ + __u8* sense=tape->devstat.ii.sense.data; + int inhibit_cu_recovery=0; + int cu_type=tape->discipline->cu_type; + if ((((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1; + if (tapestate_get(tape)==TS_BLOCK_INIT) { + // no recovery for block device, bottom half will retry... + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + if (sense[0]&SENSE_COMMAND_REJECT) + switch (tapestate_get(tape)) { + case TS_BLOCK_INIT: + case TS_DSE_INIT: + case TS_EGA_INIT: + case TS_WRI_INIT: + case TS_WTM_INIT: + if (sense[1]&SENSE_WRITE_PROTECT) { + // trying to write, but medium is write protected + tape34xx_error_recovery_has_failed(tape,EACCES); + return; + } default: - tape34xx_unexpect_uchk_handler (tape); + tape34xx_error_recovery_HWBUG(tape,1); + return; + } + // special cases for various tape-states when reaching end of recorded area + if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) && + ((sense[1]==0x40) || (sense[1]==0x0c))) + switch (tapestate_get(tape)) { + case TS_FSF_INIT: + // Trying to seek beyond end of recorded area + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case TS_LBL_INIT: + // Block could not be located. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case TS_RFO_INIT: + // Try to read beyond end of recorded area -> 0 bytes read + tape34xx_error_recovery_has_failed(tape,0); + return; + } + // Sensing special bits + if (sense[0]&SENSE_BUS_OUT_CHECK) { + tape34xx_error_recovery_do_retry(tape); + return; + } + if (sense[0]&SENSE_DATA_CHECK) { + // hardware failure, damaged tape or improper operating conditions + switch (sense[3]) { + case 0x23: + // a read data check occurred + if ((sense[2]&SENSE_TAPE_SYNC_MODE) || + (inhibit_cu_recovery)) { + // data check is not permanent, may be recovered. + // We always use async-mode with cu-recovery, so this should *never* happen. + tape34xx_error_recovery_HWBUG(tape,2); + return; + } else { + // data check is permanent, CU recovery has failed + PRINT_WARN("Permanent read error, recovery failed!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + case 0x25: + // a write data check occurred + if ((sense[2]&SENSE_TAPE_SYNC_MODE) || + (inhibit_cu_recovery)) { + // data check is not permanent, may be recovered. + // We always use async-mode with cu-recovery, so this should *never* happen. + tape34xx_error_recovery_HWBUG(tape,3); + return; + } else { + // data check is permanent, cu-recovery has failed + PRINT_WARN("Permanent write error, recovery failed!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + case 0x26: + // Data Check (read opposite) occurred. We'll recover this. + tape34xx_error_recovery_read_opposite(tape); + return; + case 0x28: + // The ID-Mark at the beginning of the tape could not be written. This is fatal, we'll report and exit. + PRINT_WARN("ID-Mark could not be written. Check your hardware!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x31: + // Tape void. Tried to read beyond end of device. We'll report and exit. + PRINT_WARN("Try to read beyond end of recorded area!\n"); + tape34xx_error_recovery_has_failed(tape,ENOSPC); + return; + case 0x41: + // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit. + PRINT_WARN("Illegal block-id sequence found!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + default: + // well, all data checks for 3480 should result in one of the above erpa-codes. if not -> bug + // On 3490, other data-check conditions do exist. + if (cu_type==0x3480) { + tape34xx_error_recovery_HWBUG(tape,4); + return; + } } } + if (sense[0]&SENSE_OVERRUN) { + // A data overrun between cu and drive occurred. The channel speed is to slow! We'll report this and exit! + switch (sense[3]) { + case 0x40: // overrun error + PRINT_WARN ("Data overrun error between control-unit and drive. Use a faster channel connection, if possible! \n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + default: + // Overrun bit is set, but erpa does not show overrun error. This is a bug. + tape34xx_error_recovery_HWBUG(tape,5); + return; + } + } + if (sense[1]&SENSE_RECORD_SEQUENCE_ERR) { + switch (sense[3]) { + case 0x41: + // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit. + PRINT_WARN("Illegal block-id sequence found!\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + default: + // Record sequence error bit is set, but erpa does not show record sequence error. This is a bug. + tape34xx_error_recovery_HWBUG(tape,6); + return; + } + } + // Sensing erpa codes + switch (sense[3]) { + case 0x00: + // Everything is fine, but we got a unit check. Report and ignore! + PRINT_WARN ("Non-error sense was found. Unit-check will be ignored, expect errors...\n"); + return; + case 0x21: + // Data streaming not operational. Cu switches to interlock mode, we reissue the command. + PRINT_WARN ("Data streaming not operational. Switching to interlock-mode! \n"); + tape34xx_error_recovery_do_retry(tape); + return; + case 0x22: + // Path equipment check. Might be drive adapter error, buffer error on the lower interface, internal path not useable, or error during cartridge load. + // All of the above are not recoverable + PRINT_WARN ("A path equipment check occurred. One of the following conditions occurred:\n"); + PRINT_WARN ("drive adapter error,buffer error on the lower interface, internal path not useable, error during cartridge load.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x23: + // Read data check. Should have been be covered earlier -> Bug! + tape34xx_error_recovery_HWBUG(tape,7); + return; + case 0x24: + // Load display check. Load display was command was issued, but the drive is displaying a drive check message. Can be threated as "device end". + tape34xx_error_recovery_succeded(tape); + return; + case 0x25: + // Write data check. Should have been covered earlier -> Bug! + tape34xx_error_recovery_HWBUG(tape,8); + return; + case 0x26: + // Data check (read opposite). Should have been covered earlier -> Bug! + tape34xx_error_recovery_HWBUG(tape,9); + return; + case 0x27: + // Command reject. May indicate illegal channel program or buffer over/underrun. + // Since all channel programms are issued by this driver and ought be correct, + // we assume a over/underrun situaltion and retry the channel program. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x28: + // Write id mark check. Should have beed covered earlier -> bug! + tape34xx_error_recovery_HWBUG(tape,10); + return; + case 0x29: + // Function incompatible. Either idrc is on but hardware not capable doing idrc + // or a perform subsystem func is issued and the cu is not online. Anyway, this + // cannot be recovered and is an I/O error. + PRINT_WARN ("Function incompatible. Try to switch off idrc! \n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x2a: + // Unsolicited environmental data. An internal counter overflows, we can ignore + // this and reissue the cmd. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x2b: + // Environmental data present. Indicates either unload completed ok or read buffered + // log command completed ok. + if (tapestate_get(tape)==TS_RUN_INIT) { + // Rewind unload completed ok. + tape34xx_error_recovery_succeded(tape); + return; + } + // Since we do not issue read buffered log commands, this should never occur -> bug. + tape34xx_error_recovery_HWBUG(tape,11); + return; + case 0x2c: + // Permanent equipment check. cu has tried recovery, but did not succeed. This is an + // I/O error. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x2d: + // Data security erase failure. + if (tapestate_get(tape)==TS_DSE_INIT) { + // report an I/O error + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + // Data security erase failure, but no such command issued. This is a bug. + tape34xx_error_recovery_HWBUG(tape,12); + return; + case 0x2e: + // Not capable. This indicates either that the drive fails reading the format id mark + // or that that format specified is not supported by the drive. We write a message and + // return an I/O error. + PRINT_WARN("Drive not capable processing the tape format!"); + tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE); + return; + case 0x2f: + // This erpa is reserved. This is a bug. + tape34xx_error_recovery_HWBUG(tape,13); + return; + case 0x30: + // The medium is write protected, while trying to write on it. We'll report this. + PRINT_WARN("Medium is write protected!\n"); + tape34xx_error_recovery_has_failed(tape,EACCES); + return; + case 0x31: + // Tape void. Should have beed covered ealier -> bug + tape34xx_error_recovery_HWBUG(tape,14); + return; + case 0x32: + // Tension loss. We cannot recover this, it's an I/O error. + PRINT_WARN("The drive lost tape tension.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x33: + // Load Failure. The catridge was not inserted correctly or the tape is not threaded + // correctly. We cannot recover this, the user has to reload the catridge. + PRINT_WARN("Cartridge load failure. Reload the cartridge and try again.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x34: + // Unload failure. The drive cannot maintain tape tension and control tape movement + // during an unload operation. + PRINT_WARN("Failure during cartridge unload. Please try manually.\n"); + if (tapestate_get(tape)!=TS_RUN_INIT) { + tape34xx_error_recovery_HWBUG(tape,15); + return; + } + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x35: + // Drive equipment check. One of the following: + // - cu cannot recover from a drive detected error + // - a check code message is displayed on drive message/load displays + // - the cartridge loader does not respond correctly + // - a failure occurs during an index, load, or unload cycle + PRINT_WARN("Equipment check! Please check the drive and the cartridge loader.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x36: + switch (cu_type) { + case 0x3480: + // This erpa is reserved for 3480 -> BUG + tape34xx_error_recovery_HWBUG(tape,16); + return; + case 0x3490: + // End of data. This is a permanent I/O error, which cannot be recovered. + // A read-type command has reached the end-of-data mark. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + } + case 0x37: + // Tape length error. The tape is shorter than reported in the beginning-of-tape data. + PRINT_WARN("Tape length error.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x38: + // Physical end of tape. A read/write operation reached the physical end of tape. + if (tapestate_get(tape)==TS_WRI_INIT) { + tape34xx_error_recovery_has_failed(tape,ENOSPC); + } + return; + case 0x39: + // Backward at BOT. The drive is at BOT and is requestet to move backward. + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x3a: + // Drive switched not ready, but the command needs the drive to be ready. + PRINT_WARN("Drive not ready. Turn the ready/not ready switch to ready position and try again.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x3b: + // Manual rewind or unload. This causes an I/O error. + PRINT_WARN("Medium is rewinded or unloaded manually.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + // These erpas are reserved -> BUG + tape34xx_error_recovery_HWBUG(tape,17); + return; + case 0x40: + // Overrun error. This should have been covered earlier -> bug. + tape34xx_error_recovery_HWBUG(tape,18); + return; + case 0x41: + // Record sequence error. This should have been covered earlier -> bug. + tape34xx_error_recovery_HWBUG(tape,19); + return; + case 0x42: + // Degraded mode. A condition that can cause degraded performace is detected. + PRINT_WARN("Subsystem is running in degraded mode. This may compromise your performace.\n"); + tape34xx_error_recovery_do_retry(tape); + return; + case 0x43: + // Drive not ready. Probably swith the ready/not ready switch to ready? + PRINT_WARN("The drive is not ready. Maybe no medium in?\n"); + tape34xx_error_recovery_has_failed(tape,ENOMEDIUM); + return; + case 0x44: + // Locate Block unsuccessfull. We'll report this. + if ((tapestate_get(tape)!=TS_BLOCK_INIT) && + (tapestate_get(tape)!=TS_LBL_INIT)) { + tape34xx_error_recovery_HWBUG(tape,20); // No locate block was issued... + return; + } + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x45: + // The drive is assigned elsewhere [to a different channel path/computer]. + PRINT_WARN("The drive is assigned elsewhere.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x46: + // Drive not online. Drive may be switched offline, the power supply may be switched off + // or the drive address may not be set correctly. + PRINT_WARN("The drive is not online."); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x47: + // Volume fenced. cu reports volume integrity is lost! + PRINT_WARN("Volume fenced. The volume integrity is lost! \n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x48: + // Log sense data and retry request. We'll do so... + tape34xx_error_recovery_do_retry(tape); + return; + case 0x49: + // Bus out check. A parity check error on the bus was found. PRINT_WARN("Bus out check. A data transfer over the bus was corrupted.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x4a: + // Control unit erp failed. We'll report this. + PRINT_WARN("The control unit failed recovering an I/O error.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x4b: + // Cu and drive incompatible. The drive requests micro-program patches, which are not available on the cu. + PRINT_WARN("The drive needs microprogram patches from the control unit, which are not available.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x4c: + // Recovered Check-One failure. Cu develops a hardware error, but is able to recover. We'll reissue the command. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x4d: + switch (cu_type) { + case 0x3480: + // This erpa is reserved for 3480 -> bug + tape34xx_error_recovery_HWBUG(tape,21); + return; + case 0x3490: + // Resetting event recieved. Since the driver does not support resetting event recovery + // (which has to be handled by the I/O Layer), we'll report and retry our command. + tape34xx_error_recovery_do_retry(tape); + return; + } + case 0x4e: + switch (cu_type) { + case 0x3480: + // This erpa is reserved for 3480 -> bug. + tape34xx_error_recovery_HWBUG(tape,22); + return; + case 0x3490: + // Maximum block size exeeded. This indicates, that the block to be written is larger + // than allowed for buffered mode. We'll report this... + PRINT_WARN("Maximum block size for buffered mode exceeded.\n"); + tape34xx_error_recovery_has_failed(tape,ENOBUFS); + return; + } + case 0x4f: + // These erpas are reserved -> bug + tape34xx_error_recovery_HWBUG(tape,23); + return; + case 0x50: + // Read buffered log (Overflow). Cu is running in extended beffered log mode, and a counter overflows. + // This should never happen, since we're never running in extended buffered log mode -> bug. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x51: + // Read buffered log (EOV). EOF processing occurs while the cu is in extended buffered log mode. + // This should never happen, since we're never running in extended buffered log mode -> bug. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x52: + // End of Volume complete. Rewind unload completed ok. We'll report to the user... + if (tapestate_get(tape)!=TS_RUN_INIT) { + tape34xx_error_recovery_HWBUG(tape,24); + return; + } + tape34xx_error_recovery_succeded(tape); + return; + case 0x53: + // Global command intercept. We'll have to reissue our command. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x54: + // Channel interface recovery (temporary). This can be recovered by reissuing the command. + tape34xx_error_recovery_do_retry(tape); + return; + case 0x55: + // Channel interface recovery (permanent). This cannot be recovered, we'll inform the user. + PRINT_WARN("A permanent channel interface error occurred.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x56: + // Channel protocol error. This cannot be recovered. + PRINT_WARN("A channel protocol error occurred.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x57: + switch (cu_type) { + case 0x3480: + // Attention intercept. We have to reissue the command. + PRINT_WARN("An attention intercept occurred, which will be recovered.\n"); + tape34xx_error_recovery_do_retry(tape); + return; + case 0x3490: + // Global status intercept. We have to reissue the command. + PRINT_WARN("An global status intercept was recieved, which will be recovered.\n"); + tape34xx_error_recovery_do_retry(tape); + return; + } + case 0x58: + case 0x59: + // These erpas are reserved -> bug. + tape34xx_error_recovery_HWBUG(tape,25); + return; + case 0x5a: + // Tape length incompatible. The tape inserted is too long, + // which could cause damage to the tape or the drive. + PRINT_WARN("Tape length incompatible [should be IBM Cartridge System Tape]. May cause damage to drive or tape.n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x5b: + // Format 3480 XF incompatible + if (sense[1]&SENSE_BEGINNING_OF_TAPE) { + // Everything is fine. The tape will be overwritten in a different format. + tape34xx_error_recovery_do_retry(tape); + return; + } + PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x5c: + // Format 3480-2 XF incompatible + PRINT_WARN("Tape format is incompatible to the drive. The drive cannot access 3480-2 XF volumes.\n"); + tape34xx_error_recovery_has_failed(tape,EIO); + return; + case 0x5d: + // Tape length violation. + PRINT_WARN("Tape length violation [should be IBM Enhanced Capacity Cartridge System Tape]. May cause damage to drive or tape.\n"); + tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE); + return; + case 0x5e: + // Compaction algorithm incompatible. + PRINT_WARN("The volume is recorded using an incompatible compaction algorith, which is not supported by the control unit.\n"); + tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE); + return; + default: + // Reserved erpas -> bug + tape34xx_error_recovery_HWBUG(tape,26); + return; + } } -void -tape34xx_wtm_init_done (tape_info_t * tape) -{ +void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id) { #ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,3,"wtm done"); + debug_text_event (tape_debug_area,3,"xerp fail"); + debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); #endif - tapestate_set (tape, TS_DONE); - tape->rc = 0; + if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) { + tape_dump_sense(&tape->devstat); + tape->rc = -error_id; tape->wanna_wakeup=1; - wake_up_interruptible (&tape->wq); + switch (tapestate_get(tape)) { + case TS_REW_RELEASE_INIT: + tapestate_set(tape,TS_FAILED); + wake_up (&tape->wq); + break; + case TS_BLOCK_INIT: + tapestate_set(tape,TS_FAILED); + schedule_tapeblock_exec_IO(tape); + break; + default: + tapestate_set(tape,TS_FAILED); + wake_up_interruptible (&tape->wq); + } + } else { + PRINT_WARN("Recieved an unsolicited IRQ.\n"); + tape_dump_sense(&tape->devstat); + } +} + +void tape34xx_error_recovery_succeded(tape_info_t* tape) { +#ifdef TAPE_DEBUG + debug_text_event (tape_debug_area,3,"xerp done"); + debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); +#endif + if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_DONE)) { + tapestate_event (tape, TE_DONE); + } else { + PRINT_WARN("Recieved an unsolicited IRQ.\n"); + tape_dump_sense(&tape->devstat); + } } -void -tape34xx_wtm_init_error (tape_info_t * tape) -{ - tape34xx_unexpect_uchk_handler (tape); +void tape34xx_error_recovery_do_retry(tape_info_t* tape) { +#ifdef TAPE_DEBUG + debug_text_event (tape_debug_area,3,"xerp retr"); + debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); +#endif + if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) { + tape_dump_sense(&tape->devstat); + while (do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 0x00, tape->cqr->options)); + } else { + PRINT_WARN("Recieved an unsolicited IRQ.\n"); + tape_dump_sense(&tape->devstat); + } +} +void +tape34xx_error_recovery_read_opposite (tape_info_t* tape) { + switch (tapestate_get(tape)) { + case TS_RFO_INIT: + // We did read forward, but the data could not be read *correctly*. + // We will read backward and then skip forward again. + tape->cqr=tape34xx_read_opposite(tape,0); + if (tape->cqr==NULL) + tape34xx_error_recovery_has_failed(tape,EIO); + else + tape34xx_error_recovery_do_retry(tape); + break; + case TS_RBA_INIT: + // We tried to read forward and backward, but hat no success -> failed. + tape34xx_error_recovery_has_failed(tape,EIO); + break; + case TS_BLOCK_INIT: + tape34xx_error_recovery_do_retry(tape); + break; + default: + PRINT_WARN("read_opposite_recovery_called_with_state:%s\n", + (((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); + } +} + +void +tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) { + devstat_t* stat=&tape->devstat; + PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno); + PRINT_WARN("Please report this incident.\n"); + PRINT_WARN("State of the tape:%s\n", + (((tapestate_get (tape) < TS_SIZE) && + (tapestate_get (tape) >= 0)) ? + state_verbose[tapestate_get (tape)] : "UNKNOWN")); + PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X " + " %02X%02X%02X%02X %02X%02X%02X%02X \n", + stat->ii.sense.data[0], stat->ii.sense.data[1], + stat->ii.sense.data[2], stat->ii.sense.data[3], + stat->ii.sense.data[4], stat->ii.sense.data[5], + stat->ii.sense.data[6], stat->ii.sense.data[7], + stat->ii.sense.data[8], stat->ii.sense.data[9], + stat->ii.sense.data[10], stat->ii.sense.data[11], + stat->ii.sense.data[12], stat->ii.sense.data[13], + stat->ii.sense.data[14], stat->ii.sense.data[15]); + PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X " + " %02X%02X%02X%02X %02X%02X%02X%02X \n", + stat->ii.sense.data[16], stat->ii.sense.data[17], + stat->ii.sense.data[18], stat->ii.sense.data[19], + stat->ii.sense.data[20], stat->ii.sense.data[21], + stat->ii.sense.data[22], stat->ii.sense.data[23], + stat->ii.sense.data[24], stat->ii.sense.data[25], + stat->ii.sense.data[26], stat->ii.sense.data[27], + stat->ii.sense.data[28], stat->ii.sense.data[29], + stat->ii.sense.data[30], stat->ii.sense.data[31]); + tape34xx_error_recovery_has_failed(tape,EIO); } diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tape34xx.h linux/drivers/s390/char/tape34xx.h --- v2.4.3/linux/drivers/s390/char/tape34xx.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tape34xx.h Wed Apr 11 19:02:28 2001 @@ -4,12 +4,11 @@ * drivers/s390/char/tape34xx.h * common tape device discipline for 34xx tapes. * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ @@ -85,6 +84,31 @@ #define CONTROL_UNIT_END DEV_STAT_CU_END /* redefine from irq.h */ #define INCORR_LEN SCHN_STAT_INCORR_LEN /* redefine from irq.h */ +#define SENSE_COMMAND_REJECT 0x80 +#define SENSE_INTERVENTION_REQUIRED 0x40 +#define SENSE_BUS_OUT_CHECK 0x20 +#define SENSE_EQUIPMENT_CHECK 0x10 +#define SENSE_DATA_CHECK 0x08 +#define SENSE_OVERRUN 0x04 +#define SENSE_DEFERRED_UNIT_CHECK 0x02 +#define SENSE_ASSIGNED_ELSEWHERE 0x01 + +#define SENSE_LOCATE_FAILURE 0x80 +#define SENSE_DRIVE_ONLINE 0x40 +#define SENSE_RESERVED 0x20 +#define SENSE_RECORD_SEQUENCE_ERR 0x10 +#define SENSE_BEGINNING_OF_TAPE 0x08 +#define SENSE_WRITE_MODE 0x04 +#define SENSE_WRITE_PROTECT 0x02 +#define SENSE_NOT_CAPABLE 0x01 + +#define SENSE_CHANNEL_ADAPTER_CODE 0xE0 +#define SENSE_CHANNEL_ADAPTER_LOC 0x10 +#define SENSE_REPORTING_CU 0x08 +#define SENSE_AUTOMATIC_LOADER 0x04 +#define SENSE_TAPE_SYNC_MODE 0x02 +#define SENSE_TAPE_POSITIONING 0x01 + typedef struct _tape34xx_disc_data_t { __u8 modeset_byte; } tape34xx_disc_data_t __attribute__ ((packed, aligned(8))); @@ -130,33 +154,30 @@ void tape34xx_default_handler (tape_info_t * tape); void tape34xx_unexpect_uchk_handler (tape_info_t * tape); void tape34xx_unused_done(tape_info_t* tape); -void tape34xx_unused_error(tape_info_t* tape); void tape34xx_idle_done(tape_info_t* tape); -void tape34xx_idle_error(tape_info_t* tape); void tape34xx_block_done(tape_info_t* tape); -void tape34xx_block_error(tape_info_t* tape); void tape34xx_bsf_init_done(tape_info_t* tape); void tape34xx_dse_init_done(tape_info_t* tape); void tape34xx_fsf_init_done(tape_info_t* tape); -void tape34xx_fsf_init_error(tape_info_t* tape); void tape34xx_bsb_init_done(tape_info_t* tape); void tape34xx_fsb_init_done(tape_info_t* tape); void tape34xx_lbl_init_done(tape_info_t* tape); -void tape34xx_lbl_init_error(tape_info_t* tape); void tape34xx_nop_init_done(tape_info_t* tape); void tape34xx_rfo_init_done(tape_info_t* tape); -void tape34xx_rfo_init_error(tape_info_t* tape); void tape34xx_rbi_init_done(tape_info_t* tape); void tape34xx_rew_init_done(tape_info_t* tape); -void tape34xx_rew_init_error(tape_info_t* tape); void tape34xx_rew_release_init_done(tape_info_t* tape); -void tape34xx_rew_release_init_error(tape_info_t* tape); void tape34xx_run_init_done(tape_info_t* tape); -void tape34xx_run_init_error(tape_info_t* tape); void tape34xx_wri_init_done(tape_info_t* tape); -void tape34xx_wri_init_error(tape_info_t* tape); void tape34xx_wtm_init_done(tape_info_t* tape); -void tape34xx_wtm_init_error(tape_info_t* tape); extern void schedule_tapeblock_exec_IO (tape_info_t *tape); + +// the error recovery stuff: +void tape34xx_error_recovery (tape_info_t* tape); +void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id); +void tape34xx_error_recovery_succeded(tape_info_t* tape); +void tape34xx_error_recovery_do_retry(tape_info_t* tape); +void tape34xx_error_recovery_read_opposite (tape_info_t* tape); +void tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno); #endif // _TAPE34XX_H diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapeblock.c linux/drivers/s390/char/tapeblock.c --- v2.4.3/linux/drivers/s390/char/tapeblock.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tapeblock.c Thu Apr 12 12:16:35 2001 @@ -4,15 +4,17 @@ * drivers/s390/char/tapeblock.c * block device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #include "tapedefs.h" +#include <linux/config.h> #include <linux/blkdev.h> #include <linux/blk.h> #include <linux/version.h> @@ -22,6 +24,7 @@ #include <asm/s390dyn.h> #include <linux/compatmac.h> #ifdef MODULE +#define __NO_VERSION__ #include <linux/module.h> #endif #include "tape.h" @@ -51,6 +54,21 @@ static request_queue_t* tapeblock_getqueue (kdev_t kdev); +#ifdef CONFIG_DEVFS_FS +void +tapeblock_mkdevfstree (tape_info_t* tape) { + tape->devfs_block_dir=devfs_mk_dir (tape->devfs_dir, "block", tape); + tape->devfs_disc=devfs_register(tape->devfs_block_dir, "disc",DEVFS_FL_DEFAULT, + tapeblock_major, tape->blk_minor, + TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, tape); +} + +void +tapeblock_rmdevfstree (tape_info_t* tape) { + devfs_unregister(tape->devfs_disc); + devfs_unregister(tape->devfs_block_dir); +} +#endif void tapeblock_setup(tape_info_t* tape) { @@ -59,9 +77,12 @@ hardsect_size[tapeblock_major][tape->blk_minor]=512; blk_init_queue (&tape->request_queue, tape_request_fn); blk_queue_headactive (&tape->request_queue, 0); +#ifdef CONFIG_DEVFS_FS + tapeblock_mkdevfstree(tape); +#endif } -void +int tapeblock_init(void) { int result; tape_frontend_t* blkfront,*temp; @@ -69,7 +90,11 @@ tape_init(); /* Register the tape major number to the kernel */ +#ifdef CONFIG_DEVFS_FS + result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops); +#else result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops); +#endif if (result < 0) { PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major); panic ("cannot get major number for tape block device"); @@ -89,6 +114,10 @@ blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL); if (blkfront==NULL) panic ("no mem for tape block device structure"); blkfront->device_setup=tapeblock_setup; +#ifdef CONFIG_DEVFS_FS + blkfront->mkdevfstree = tapeblock_mkdevfstree; + blkfront->rmdevfstree = tapeblock_rmdevfstree; +#endif blkfront->next=NULL; if (first_frontend==NULL) { first_frontend=blkfront; @@ -103,6 +132,7 @@ tapeblock_setup(tape); tape=tape->next; } + return 0; } @@ -111,7 +141,7 @@ unregister_blkdev(tapeblock_major, "tBLK"); } -static int +int tapeblock_open(struct inode *inode, struct file *filp) { tape_info_t *ti; kdev_t dev; @@ -140,7 +170,7 @@ ti->position=-1; s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); - rc=tapeblock_mediumdetect(ti); + rc=tapeblock_mediumdetect(ti); if (rc) return rc; // in case of errors, we don't have a size of the medium dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev)); /* Get the device */ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); @@ -155,12 +185,10 @@ return 0; } -static int +int tapeblock_release(struct inode *inode, struct file *filp) { long lockflags; tape_info_t *ti,*lastti; - - inode = filp->f_dentry->d_inode; ti = first_tape_info; while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev))) ti = (tape_info_t *) ti->next; @@ -177,7 +205,7 @@ } if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) { #ifdef TAPE_DEBUG - debug_text_event (tape_debug_area,6,"b:notidle!"); + debug_text_event (tape_debug_area,3,"b:notidle!"); #endif return -ENXIO; /* error in tape_release */ } @@ -191,6 +219,7 @@ #ifdef MODULE MOD_DEC_USE_COUNT; #endif /* MODULE */ + invalidate_buffers(inode->i_rdev); return 0; } @@ -226,7 +255,7 @@ tape->discipline->free_bread(tape->cqr,tape); tape->cqr=NULL; tape->current_request=NULL; - tapestate_set(tape,TS_IDLE); + if (tapestate_get(tape)!=TS_NOT_OPER) tapestate_set(tape,TS_IDLE); return; } @@ -258,7 +287,17 @@ tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl } if (tape->cqr!=NULL) BUG(); // tape should be idle now, request should be freed! - if (list_empty(&tape->request_queue.queue_head)) { // nothing more to do ;) + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + return; + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + if (list_empty (&tape->request_queue.queue_head)) { +#else + if (tape->request_queue==NULL) { +#endif + // nothing more to do or device has dissapeared;) #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"b:Qempty"); #endif @@ -342,8 +381,9 @@ if (atomic_compare_and_swap(0,1,&tape->bh_scheduled)) { return; } - +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) INIT_LIST_HEAD(&tape->bh_tq.list); +#endif tape->bh_tq.sync = 0; tape->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO; tape->bh_tq.data = tape; @@ -376,13 +416,14 @@ return NULL; } -static int tapeblock_mediumdetect(tape_info_t* tape) { - ccw_req_t* cqr; +int tapeblock_mediumdetect(tape_info_t* tape) { + ccw_req_t* cqr; int losize=1,hisize=1,rc; long lockflags; #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"b:medDet"); #endif + PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...\n"); while (1) { //is interruped by break hisize=hisize << 1; // try twice the size tested before cqr=tape->discipline->mtseek (tape, hisize); @@ -415,6 +456,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); break; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -449,6 +496,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); return -EIO; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -482,6 +535,12 @@ return -ERESTARTSYS; } s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags); + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) == TS_FAILED) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapeblock.h linux/drivers/s390/char/tapeblock.h --- v2.4.3/linux/drivers/s390/char/tapeblock.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tapeblock.h Thu Apr 12 12:16:35 2001 @@ -4,23 +4,33 @@ * drivers/s390/char/tapechar.h * character device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #ifndef TAPEBLOCK_H #define TAPEBLOCK_H +#include <linux/config.h> #define PARTN_BITS 0 #define TAPEBLOCK_READAHEAD 30 #define TAPEBLOCK_MAJOR 0 -static int tapeblock_open(struct inode *, struct file *); -static int tapeblock_release(struct inode *, struct file *); + +#define TAPEBLOCK_DEFAULTMODE 0060644 + +int tapeblock_open(struct inode *, struct file *); +int tapeblock_release(struct inode *, struct file *); void tapeblock_setup(tape_info_t* tape); void schedule_tapeblock_exec_IO (tape_info_t *tape); -static int tapeblock_mediumdetect(tape_info_t* tape); +int tapeblock_mediumdetect(tape_info_t* tape); +#ifdef CONFIG_DEVFS_FS +void tapeblock_mkdevfstree (tape_info_t* tape); +#endif +int tapeblock_init (void); +void tapeblock_uninit (void); #endif diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapechar.c linux/drivers/s390/char/tapechar.c --- v2.4.3/linux/drivers/s390/char/tapechar.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tapechar.c Thu Apr 12 12:16:35 2001 @@ -4,16 +4,17 @@ * drivers/s390/char/tapechar.c * character device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #include "tapedefs.h" +#include <linux/config.h> #include <linux/version.h> #include <linux/types.h> #include <linux/proc_fs.h> @@ -24,6 +25,7 @@ #include <asm/uaccess.h> #include <linux/compatmac.h> #ifdef MODULE +#define __NO_VERSION__ #include <linux/module.h> #endif #include "tape.h" @@ -54,10 +56,33 @@ int tape_major = TAPE_MAJOR; +#ifdef CONFIG_DEVFS_FS +void +tapechar_mkdevfstree (tape_info_t* tape) { + tape->devfs_char_dir=devfs_mk_dir (tape->devfs_dir, "char", tape); + tape->devfs_nonrewinding=devfs_register(tape->devfs_char_dir, "nonrewinding", + DEVFS_FL_DEFAULT,tape_major, + tape->nor_minor, TAPECHAR_DEFAULTMODE, + &tape_fops, tape); + tape->devfs_rewinding=devfs_register(tape->devfs_char_dir, "rewinding", + DEVFS_FL_DEFAULT, tape_major, tape->rew_minor, + TAPECHAR_DEFAULTMODE, &tape_fops, tape); +} + +void +tapechar_rmdevfstree (tape_info_t* tape) { + devfs_unregister(tape->devfs_nonrewinding); + devfs_unregister(tape->devfs_rewinding); + devfs_unregister(tape->devfs_char_dir); +} +#endif + void tapechar_setup (tape_info_t * tape) { - // nothing to do +#ifdef CONFIG_DEVFS_FS + tapechar_mkdevfstree(tape); +#endif } void @@ -70,7 +95,11 @@ tape_init(); /* Register the tape major number to the kernel */ +#ifdef CONFIG_DEVFS_FS + result = devfs_register_chrdev (tape_major, "tape", &tape_fops); +#else result = register_chrdev (tape_major, "tape", &tape_fops); +#endif if (result < 0) { PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tape_major); @@ -92,6 +121,10 @@ panic ("no major number available for tape char device"); } charfront->device_setup = tapechar_setup; +#ifdef CONFIG_DEVFS_FS + charfront->mkdevfstree = tapechar_mkdevfstree; + charfront->rmdevfstree = tapechar_rmdevfstree; +#endif #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"c:init ok"); #endif /* TAPE_DEBUG */ @@ -120,7 +153,7 @@ /* * Tape device read function */ -static ssize_t +ssize_t tape_read (struct file *filp, char *data, size_t count, loff_t * ppos) { long lockflags; @@ -184,6 +217,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); return tape->rc; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -202,7 +241,7 @@ /* * Tape device write function */ -static ssize_t +ssize_t tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos) { long lockflags; @@ -262,8 +301,16 @@ if (tapestate_get (tape) == TS_FAILED) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); + if ((tape->rc==-ENOSPC) && (i!=0)) + return i*block_size; return tape->rc; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -446,6 +493,12 @@ s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); return tape->rc; } + if (tapestate_get (tape) == TS_NOT_OPER) { + tape->blk_minor=tape->rew_minor=tape->nor_minor=-1; + tape->devinfo.irq=-1; + s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags); + return -ENODEV; + } if (tapestate_get (tape) != TS_DONE) { tapestate_set (tape, TS_IDLE); s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags); @@ -473,7 +526,7 @@ /* * Tape device io controls. */ -static int +int tape_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -589,7 +642,7 @@ /* * Tape device open function. */ -static int +int tape_open (struct inode *inode, struct file *filp) { tape_info_t *ti; @@ -637,7 +690,7 @@ /* * Tape device release function. */ -static int +int tape_release (struct inode *inode, struct file *filp) { long lockflags; @@ -645,7 +698,6 @@ ccw_req_t *cqr = NULL; int rc; - inode = filp->f_dentry->d_inode; ti = first_tape_info; while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev))) ti = (tape_info_t *) ti->next; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapechar.h linux/drivers/s390/char/tapechar.h --- v2.4.3/linux/drivers/s390/char/tapechar.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tapechar.h Thu Apr 12 12:16:35 2001 @@ -4,24 +4,31 @@ * drivers/s390/char/tapechar.h * character device frontend for tape device driver * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> + * * - * UNDER CONSTRUCTION: Work in progress...:-) **************************************************************************** */ #ifndef TAPECHAR_H #define TAPECHAR_H +#include <linux/config.h> +#define TAPECHAR_DEFAULTMODE 0020644 #define TAPE_MAJOR 0 /* get dynamic major since no major officialy defined for tape */ /* * Prototypes for tape_fops */ -static ssize_t tape_read(struct file *, char *, size_t, loff_t *); -static ssize_t tape_write(struct file *, const char *, size_t, loff_t *); -static int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long); -static int tape_open (struct inode *,struct file *); -static int tape_release (struct inode *,struct file *); +ssize_t tape_read(struct file *, char *, size_t, loff_t *); +ssize_t tape_write(struct file *, const char *, size_t, loff_t *); +int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long); +int tape_open (struct inode *,struct file *); +int tape_release (struct inode *,struct file *); +#ifdef CONFIG_DEVFS_FS +void tapechar_mkdevfstree (tape_info_t* tape); +#endif +void tapechar_init (void); +void tapechar_uninit (void); #endif /* TAPECHAR_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tapedefs.h linux/drivers/s390/char/tapedefs.h --- v2.4.3/linux/drivers/s390/char/tapedefs.h Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/char/tapedefs.h Wed Apr 11 19:02:28 2001 @@ -1,19 +1,19 @@ /*********************************************************************** * drivers/s390/char/tapedefs.h - * tape device driver for S/390 tapes. + * tape device driver for S/390 and zSeries tapes. + * + * S390 and zSeries version + * Copyright (C) 2001 IBM Corporation + * Author(s): Carsten Otte <cotte@de.ibm.com> + * Tuan Ngo-Anh <ngoanh@de.ibm.com> * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s): Tuan Ngo-Anh <ngoanh@de.ibm.com> - * Carsten Otte <cotte@de.ibm.com> * - * UNDER CONSTRUCTION: Work in progress... :-) *********************************************************************** */ -#define TAPE_DEBUG -#define CONFIG_S390_TAPE_DYNAMIC //use dyn. dev. attach/detach -#define TAPEBLOCK_RETRIES 20 +#define TAPE_DEBUG // use s390 debug feature +#define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly +#define TAPEBLOCK_RETRIES 20 // number of retries, when a block-dev request fails. /* Kernel Version Compatibility section */ @@ -36,8 +36,11 @@ blkdev_dequeue_request (req); } #else +#define s390_dev_info_t dev_info_t typedef struct request *request_queue_t; +#ifndef init_waitqueue_head #define init_waitqueue_head(x) do { *x = NULL; } while(0) +#endif #define blk_init_queue(x,y) do {} while(0) #define blk_queue_headactive(x,y) do {} while(0) #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tuball.c linux/drivers/s390/char/tuball.c --- v2.4.3/linux/drivers/s390/char/tuball.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tuball.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,625 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tuball.c -- Initialization, termination, irq lookup + * + * + * + * + * + * Author: Richard Hitt + */ +#include <linux/config.h> +#include "tubio.h" +#ifndef MODULE +#include <linux/init.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +#include "../../../arch/s390/kernel/cpcmd.h" +#include <linux/bootmem.h> +#else +#include "../../../../arch/s390/kernel/cpcmd.h" +#endif +#endif + +/* Module parameters */ +int tubdebug; +int tubscrolltime; +int tubscrollparm; +int tubxcorrect = 1; /* Do correct ebc<->asc tables */ +#ifdef MODULE +MODULE_PARM(tubdebug, "i"); +MODULE_PARM(tubscrolltime, "i"); +MODULE_PARM(tubxcorrect, "i"); +#endif +/* + * Values for tubdebug and their effects: + * 1 - print in hex on console the first 16 bytes received + * 2 - print address at which array tubminors is allocated + * 4 - attempt to register tty3270_driver + */ +int tubnummins; +tub_t *(*tubminors)[TUBMAXMINS]; +tub_t *(*(*tubirqs)[256])[256]; +unsigned char tub_ascebc[256]; +unsigned char tub_ebcasc[256]; +int tubinitminors(void); +void tubfiniminors(void); +void tubint(int, void *, struct pt_regs *); + +/* Lookup-by-irq functions */ +int tubaddbyirq(tub_t *, int); +tub_t *tubfindbyirq(int); +void tubdelbyirq(tub_t *, int); +void tubfiniirqs(void); + +extern int fs3270_init(void); +extern void fs3270_fini(void); +extern int tty3270_init(void); +extern void tty3270_fini(void); + +unsigned char tub_ebcgraf[64] = + { 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f }; + +static int tub3270_init(void); + +#ifndef MODULE + +/* + * Can't have this driver a module & support console at the same time + */ +#ifdef CONFIG_3270_CONSOLE +static kdev_t tub3270_con_device(struct console *); +static void tub3270_con_unblank(void); +static void tub3270_con_write(struct console *, const char *, + unsigned int); + +static struct console tub3270_con = { + "tub3270", /* name */ + tub3270_con_write, /* write */ + NULL, /* read */ + tub3270_con_device, /* device */ + NULL, /* wait_key */ + tub3270_con_unblank, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, /* flags */ + 0, /* index */ + 0, /* cflag */ + NULL /* next */ +}; + +int tub3270_con_devno = -1; /* set by tub3270_con_setup() */ +bcb_t tub3270_con_bcb; /* Buffer that receives con writes */ +spinlock_t tub3270_con_bcblock; /* Lock for the buffer */ +int tub3270_con_irq = -1; /* set nonneg by _activate() */ +tub_t *tub3270_con_tubp; /* set nonzero by _activate() */ +struct tty_driver tty3270_con_driver; /* for /dev/console at 4, 64 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +__initfunc(void tub3270_con_setup(char *str, int *ints)) +#else +static int __init tub3270_con_setup(char *str) +#endif +{ + int vdev; + + vdev = simple_strtoul(str, 0, 16); + if (vdev >= 0 && vdev < 65536) + tub3270_con_devno = vdev; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + return; +#else + return 1; +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +__setup("condev=", tub3270_con_setup); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +__initfunc (long tub3270_con_init(long kmem_start, long kmem_end)) +#else +void __init tub3270_con_init(void) +#endif +{ + tub3270_con_bcb.bc_len = 65536; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + if (!MACHINE_IS_VM && !MACHINE_IS_P390) + return kmem_start; + tub3270_con_bcb.bc_buf = (void *)kmem_start; + kmem_start += tub3270_con_bcb.bc_len; + register_console(&tub3270_con); + return kmem_start; +#else + if (!MACHINE_IS_VM && !MACHINE_IS_P390) + return; + tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low( + tub3270_con_bcb.bc_len); + register_console(&tub3270_con); +#endif +} + +static kdev_t +tub3270_con_device(struct console *conp) +{ + return MKDEV(IBM_TTY3270_MAJOR, conp->index); +} + +static void +tub3270_con_unblank(void) +{ + /* flush everything: panic has occurred */ +} + +int tub3270_con_write_deadlock_ct; +int tub3270_con_write_deadlock_bytes; +static void +tub3270_con_write(struct console *conp, + const char *buf, unsigned int count) +{ + int flags; + tub_t *tubp = tub3270_con_tubp; + void tty3270_sched_bh(tub_t *); + int rc; + bcb_t obcb; + + obcb.bc_buf = (char *)buf; + obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = + MIN(count, tub3270_con_bcb.bc_len); + obcb.bc_rd = 0; + + spin_lock_irqsave(&tub3270_con_bcblock, flags); + rc = tub3270_movedata(&obcb, &tub3270_con_bcb); + spin_unlock_irqrestore(&tub3270_con_bcblock, flags); + + if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) { + tty3270_sched_bh(tubp); + TUBUNLOCK(tubp->irq, flags); + } +} + +int tub3270_con_copy(tub_t *tubp) +{ + int flags; + int rc; + + spin_lock_irqsave(&tub3270_con_bcblock, flags); + rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb); + spin_unlock_irqrestore(&tub3270_con_bcblock, flags); + return rc; +} +#endif /* CONFIG_3270_CONSOLE */ + + + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +__initfunc(void tub3270_initfunc(void)) +#else +void __init tub3270_initfunc(void) +#endif +{ + tub3270_init(); +} +#else /* If generated as a MODULE */ +/* + * module init: find tubes; get a major nbr + */ +int +init_module(void) +{ + if (tubnummins != 0) { + printk(KERN_ERR "EEEK!! Tube driver cobbigling!!\n"); + return -1; + } + return tub3270_init(); +} + +/* + * remove driver: unregister the major number + */ +void +cleanup_module(void) +{ + fs3270_fini(); + tty3270_fini(); + tubfiniminors(); +} +#endif /* Not a MODULE or a MODULE */ + +void +tub_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void +tub_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +/* + * tub3270_init() called by kernel or module initialization + */ +static int +tub3270_init(void) +{ + s390_dev_info_t d; + int i, rc; + + /* + * Initialize default scrolltime to either -1 or the + * module parameter tubscrolltime. + */ + if (tubscrolltime) + tubscrollparm = tubscrolltime; + else + tubscrollparm = -1; + + /* + * Copy and correct ebcdic - ascii translate tables + */ + memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc); + memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc); + if (tubxcorrect) { + /* correct brackets and circumflex */ + tub_ascebc['['] = 0xad; + tub_ascebc[']'] = 0xbd; + tub_ebcasc[0xad] = '['; + tub_ebcasc[0xbd] = ']'; + tub_ascebc['^'] = 0xb0; + tub_ebcasc[0x5f] = '^'; + } + + rc = tubinitminors(); + if (rc != 0) + return rc; + + for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) { + if ((rc = get_dev_info_by_irq(i, &d))) + continue; + if (d.status) + continue; +#ifdef CONFIG_3270_CONSOLE + if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) { + cpcmd("TERM CONMODE 3270", NULL, 0); + d.sid_data.cu_type = 0x3270; + } +#endif /* CONFIG_3270_CONSOLE */ + if ((d.sid_data.cu_type & 0xfff0) != 0x3270) + continue; + + rc = tubmakemin(i, &d); + if (rc < 0) { + if (tubnummins == 1) { /* if first time */ + tubfiniminors(); + printk(KERN_ERR "No kernel memory available" + " for 3270 tube devices.\n"); + return rc; + } + printk(KERN_WARNING "3270 tube registration ran out of memory" + " after %d devices\n", tubnummins - 1); + break; + } else { + printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n", + d.devno, d.irq, rc); + } + } + + if (fs3270_init() || tty3270_init()) { + printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n"); + fs3270_fini(); + tty3270_fini(); + tubfiniminors(); + return -1; + } + + return 0; +} + +/* + * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream + */ +int +tub3270_movedata(bcb_t *ib, bcb_t *ob) +{ + int count; /* Total move length */ + int rc; + + rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt); + while (count > 0) { + int len1; /* Contig bytes avail in ib */ + + if (ib->bc_wr > ib->bc_rd) + len1 = ib->bc_wr - ib->bc_rd; + else + len1 = ib->bc_len - ib->bc_rd; + if (len1 > count) + len1 = count; + + while (len1 > 0) { + int len2; /* Contig space avail in ob */ + + if (ob->bc_rd > ob->bc_wr) + len2 = ob->bc_rd - ob->bc_wr; + else + len2 = ob->bc_len - ob->bc_wr; + if (len2 > len1) + len2 = len1; + + memcpy(ob->bc_buf + ob->bc_wr, + ib->bc_buf + ib->bc_rd, + len2); + + ib->bc_rd += len2; + if (ib->bc_rd == ib->bc_len) + ib->bc_rd = 0; + ib->bc_cnt -= len2; + + ob->bc_wr += len2; + if (ob->bc_wr == ob->bc_len) + ob->bc_wr = 0; + ob->bc_cnt += len2; + + len1 -= len2; + count -= len2; + } + } + return rc; +} + +/* + * receive an interrupt + */ +void +tubint(int irq, void *ipp, struct pt_regs *prp) +{ + devstat_t *dsp = ipp; + tub_t *tubp; + + if ((tubp = IRQ2TUB(irq)) && (tubp->intv)) + (tubp->intv)(tubp, dsp); +} + +/* + * Initialize array of pointers to minor structures tub_t. + * Returns 0 or -ENOMEM. + */ +int +tubinitminors(void) +{ + tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors, + GFP_KERNEL); + if (tubminors == NULL) + return -ENOMEM; + memset(tubminors, 0, sizeof *tubminors); + return 0; +} + +/* + * Add a minor 327x device. Argument is an irq value. + * + * Point elements of two arrays to the newly created tub_t: + * 1. (*tubminors)[minor] + * 2. (*(*tubirqs)[irqhi])[irqlo] + * The first looks up from minor number at context time; the second + * looks up from irq at interrupt time. + */ +int +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +tubmakemin(int irq, dev_info_t *dp) +#else +tubmakemin(int irq, s390_dev_info_t *dp) +#endif +{ + tub_t *tubp; + int minor; + int flags; + + if ((minor = ++tubnummins) == TUBMAXMINS) + return -ENODEV; + + tubp = kmalloc(sizeof(tub_t), GFP_KERNEL); + if (tubp == NULL) { + return -ENOMEM; + } + if (tubaddbyirq(tubp, irq) != 0) { + kfree(tubp); + return -ENOMEM; + } + memset(tubp, 0, sizeof(tub_t)); + tubp->minor = minor; + tubp->irq = irq; + TUBLOCK(tubp->irq, flags); + tubp->devno = dp->devno; + tubp->geom_rows = _GEOM_ROWS; + tubp->geom_cols = _GEOM_COLS; + init_waitqueue_head(&tubp->waitq); + + tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE; + tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len, + GFP_KERNEL); + if (tubp->tty_bcb.bc_buf == NULL) { + TUBUNLOCK(tubp->irq, flags); + tubdelbyirq(tubp, irq); + kfree(tubp); + return -ENOMEM; + } + tubp->tty_bcb.bc_cnt = 0; + tubp->tty_bcb.bc_wr = 0; + tubp->tty_bcb.bc_rd = 0; + (*tubminors)[minor] = tubp; +#ifdef CONFIG_3270_CONSOLE + if (tub3270_con_tubp == NULL && tub3270_con_bcb.bc_buf != NULL && + (tub3270_con_devno == -1 || + tub3270_con_devno == dp->devno)) { + extern void tty3270_int(tub_t *, devstat_t *); + + tubp->cmd = TBC_CONOPEN; + tubp->flags |= TUB_OPEN_STET; + tty3270_size(tubp, &flags); + tty3270_aid_init(tubp); + tty3270_scl_init(tubp); + tub3270_con_irq = tubp->irq; + tub3270_con_tubp = tubp; + tubp->intv = tty3270_int; + tubp->cmd = TBC_UPDSTAT; + tty3270_build(tubp); + } +#endif /* CONFIG_3270_CONSOLE */ + TUBUNLOCK(tubp->irq, flags); + return minor; +} + +/* + * Release array of pointers to minor structures tub_t, but first + * release any storage pointed to by them. + */ +void +tubfiniminors(void) +{ + int i; + tub_t **tubpp, *tubp; + + if (tubminors == NULL) + return; + + for (i = 0; i < TUBMAXMINS; i++) { + tubpp = &(*tubminors)[i]; + if ((tubp = *tubpp)) { + tubdelbyirq(tubp, tubp->irq); + tty3270_rcl_fini(tubp); + kfree(tubp->tty_bcb.bc_buf); + tubp->tty_bcb.bc_buf = NULL; + tubp->ttyscreen = NULL; + kfree(tubp); + *tubpp = NULL; + } + } + kfree(tubminors); + tubminors = NULL; + tubfiniirqs(); +} + +/* + * tubaddbyirq() -- Add tub_t for irq lookup in tubint() + */ +int +tubaddbyirq(tub_t *tubp, int irq) +{ + int irqhi = (irq >> 8) & 255; + int irqlo = irq & 255; + tub_t *(*itubpp)[256]; + + /* Allocate array (*tubirqs)[] if first time */ + if (tubirqs == NULL) { + tubirqs = (tub_t *(*(*)[256])[256]) + kmalloc(sizeof *tubirqs, GFP_KERNEL); + if (tubirqs == NULL) + return -ENOMEM; + memset(tubirqs, 0, sizeof *tubirqs); + } + + /* Allocate subarray (*(*tubirqs)[])[] if first use */ + if ((itubpp = (*tubirqs)[irqhi]) == NULL) { + itubpp = (tub_t *(*)[256]) + kmalloc(sizeof(*itubpp), GFP_KERNEL); + if (itubpp == NULL) { + if (tubnummins == 1) { /* if first time */ + kfree(tubirqs); + tubirqs = NULL; + } + return -ENOMEM; + } else { + memset(itubpp, 0, sizeof(*itubpp)); + (*tubirqs)[irqhi] = itubpp; + } + } + + /* Request interrupt service */ + if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT, + "3270 tube driver", &tubp->devstat)) != 0) + return tubp->irqrc; + + /* Fill in the proper subarray element */ + (*itubpp)[irqlo] = tubp; + return 0; +} + +/* + * tubfindbyirq(irq) + */ +tub_t * +tubfindbyirq(int irq) +{ + int irqhi = (irq >> 8) & 255; + int irqlo = irq & 255; + tub_t *tubp; + + if (tubirqs == NULL) + return NULL; + if ((*tubirqs)[irqhi] == NULL) + return NULL; + tubp = (*(*tubirqs)[irqhi])[irqlo]; + if (tubp->irq == irq) + return tubp; + return NULL; +} + +/* + * tubdelbyirq(tub_t*, irq) + */ +void +tubdelbyirq(tub_t *tubp, int irq) +{ + int irqhi = (irq >> 8) & 255; + int irqlo = irq & 255; + tub_t *(*itubpp)[256], *itubp; + + if (tubirqs == NULL) { + printk(KERN_ERR "tubirqs is NULL\n"); + return; + } + itubpp = (*tubirqs)[irqhi]; + if (itubpp == NULL) { + printk(KERN_ERR "tubirqs[%d] is NULL\n", irqhi); + return; + } + itubp = (*itubpp)[irqlo]; + if (itubp == NULL) { + printk(KERN_ERR "tubirqs[%d][%d] is NULL\n", irqhi, irqlo); + return; + } + if (itubp->irqrc == 0) + free_irq(irq, &itubp->devstat); + (*itubpp)[irqlo] = NULL; +} + +/* + * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256] + */ +void +tubfiniirqs(void) +{ + int i; + tub_t *(*itubpp)[256]; + + if (tubirqs != NULL) { + for (i = 0; i < 256; i++) { + if ((itubpp = (*tubirqs)[i])) { + kfree(itubpp); + (*tubirqs)[i] = NULL; + } + } + kfree(tubirqs); + tubirqs = NULL; + } +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubfs.c linux/drivers/s390/char/tubfs.c --- v2.4.3/linux/drivers/s390/char/tubfs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubfs.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,404 @@ +/* + * IBM/3270 Driver -- Copyright (C) UTS Global LLC + * + * tubfs.c -- Fullscreen driver + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + +int fs3270_major = -1; /* init to impossible -1 */ + +static int fs3270_open(struct inode *, struct file *); +static int fs3270_close(struct inode *, struct file *); +static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static int fs3270_read(struct file *, char *, size_t, loff_t *); +static int fs3270_write(struct file *, const char *, size_t, loff_t *); +static int fs3270_wait(tub_t *, int *); +static void fs3270_int(tub_t *tubp, devstat_t *dsp); +extern void tty3270_refresh(tub_t *); + +static struct file_operations fs3270_fops = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) + owner: THIS_MODULE, /* owner */ +#endif + read: fs3270_read, /* read */ + write: fs3270_write, /* write */ + ioctl: fs3270_ioctl, /* ioctl */ + open: fs3270_open, /* open */ + release:fs3270_close, /* release */ +}; + +/* + * fs3270_init() -- Initialize fullscreen tubes + */ +int +fs3270_init(void) +{ + int rc; + + rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops); + if (rc) { + printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n", + IBM_FS3270_MAJOR, rc); + return -1; + } else { + fs3270_major = IBM_FS3270_MAJOR; + return 0; + } +} + +/* + * fs3270_fini() -- Uninitialize fullscreen tubes + */ +void +fs3270_fini(void) +{ + if (fs3270_major != -1) { + unregister_chrdev(fs3270_major, "fs3270"); + fs3270_major = -1; + } +} + +/* + * fs3270_open + */ +static int +fs3270_open(struct inode *ip, struct file *fp) +{ + tub_t *tubp; + int flags; + + /* See INODE2TUB(ip) for handling of "/dev/3270/tub" */ + if ((tubp = INODE2TUB(ip)) == NULL) + return -ENOENT; + + TUBLOCK(tubp->irq, flags); + if (tubp->mode == TBM_FS || tubp->mode == TBM_FSLN) { + TUBUNLOCK(tubp->irq, flags); + return -EBUSY; + } + + tub_inc_use_count(); + fp->private_data = ip; + tubp->mode = TBM_FS; + tubp->intv = fs3270_int; + tubp->dstat = 0; + tubp->fs_pid = current->pid; + tubp->fsopen = 1; + TUBUNLOCK(tubp->irq, flags); + return 0; +} + +/* + * fs3270_close aka release: free the irq + */ +static int +fs3270_close(struct inode *ip, struct file *fp) +{ + tub_t *tubp; + int flags; + + if ((tubp = INODE2TUB(ip)) == NULL) + return -ENODEV; + + fs3270_wait(tubp, &flags); + tubp->fsopen = 0; + tubp->fs_pid = 0; + tub_dec_use_count(); + tubp->intv = NULL; + tubp->mode = 0; + tty3270_refresh(tubp); + TUBUNLOCK(tubp->irq, flags); + return 0; +} + +/* + * fs3270_release() called from tty3270_hangup() + */ +void +fs3270_release(tub_t *tubp) +{ + int flags; + + if (tubp->mode != TBM_FS) + return; + fs3270_wait(tubp, &flags); + tubp->fsopen = 0; + tubp->fs_pid = 0; + tub_dec_use_count(); + tubp->intv = NULL; + tubp->mode = 0; + /*tty3270_refresh(tubp);*/ + TUBUNLOCK(tubp->irq, flags); +} + +/* + * fs3270_wait(tub_t *tubp, int *flags) -- Wait to use tube + * Entered without irq lock + * On return: + * * Lock is held + * * Value is 0 or -ERESTARTSYS + */ +static int +fs3270_wait(tub_t *tubp, int *flags) +{ + DECLARE_WAITQUEUE(wait, current); + + TUBLOCK(tubp->irq, *flags); + add_wait_queue(&tubp->waitq, &wait); + while (!signal_pending(current) && + ((tubp->mode != TBM_FS) || + (tubp->flags & (TUB_WORKING | TUB_RDPENDING)) != 0)) { + current->state = TASK_INTERRUPTIBLE; + TUBUNLOCK(tubp->irq, *flags); + schedule(); + current->state = TASK_RUNNING; + TUBLOCK(tubp->irq, *flags); + } + remove_wait_queue(&tubp->waitq, &wait); + return signal_pending(current)? -ERESTARTSYS: 0; +} + +/* + * fs3270_io(tubp, ccw1_t*) -- start I/O on the tube + * Entered with irq lock held, WORKING off + */ +static int +fs3270_io(tub_t *tubp, ccw1_t *ccwp) +{ + int rc; + + rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0); + tubp->flags |= TUB_WORKING; + tubp->dstat = 0; + return rc; +} + +/* + * fs3270_bh(tubp) -- Perform back-half processing + */ +static void +fs3270_bh(void *data) +{ + int flags; + tub_t *tubp; + + tubp = data; + TUBLOCK(tubp->irq, flags); + tubp->flags &= ~TUB_BHPENDING; + + if (tubp->wbuf) { /* if we were writing */ + kfree(tubp->wbuf); + tubp->wbuf = NULL; + } + + if ((tubp->flags & (TUB_ATTN | TUB_RDPENDING)) == + (TUB_ATTN | TUB_RDPENDING)) { + fs3270_io(tubp, &tubp->rccw); + tubp->flags &= ~(TUB_ATTN | TUB_RDPENDING); + } + + if ((tubp->flags & TUB_WORKING) == 0) + wake_up_interruptible(&tubp->waitq); + + TUBUNLOCK(tubp->irq, flags); +} + +/* + * fs3270_sched_bh(tubp) -- Schedule the back half + * Irq lock must be held on entry and remains held on exit. + */ +static void +fs3270_sched_bh(tub_t *tubp) +{ + if (tubp->flags & TUB_BHPENDING) + return; + tubp->flags |= TUB_BHPENDING; + tubp->tqueue.routine = fs3270_bh; + tubp->tqueue.data = tubp; + queue_task(&tubp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * fs3270_int(tubp, prp) -- Process interrupt from tube in FS mode + * This routine is entered with irq lock held (see do_IRQ in s390io.c) + */ +static void +fs3270_int(tub_t *tubp, devstat_t *dsp) +{ +#define DEV_UE_BUSY \ + (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP) + + tubp->dstat = dsp->dstat; + +#ifdef RBHNOTYET + /* XXX needs more work; must save 2d arg to fs370_io() */ + /* Handle CE-DE-UE and subsequent UDE */ + if (dsp->dstat == DEV_UE_BUSY) { + tubp->flags |= TUB_UE_BUSY; + return; + } else if (tubp->flags & TUB_UE_BUSY) { + tubp->flags &= ~TUB_UE_BUSY; + if (dsp->dstat == DEV_STAT_DEV_END && + (tubp->flags & TUB_WORKING) != 0) { + fs3270_io(tubp); + return; + } + } +#endif + + /* Handle ATTN */ + if (dsp->dstat & DEV_STAT_ATTENTION) + tubp->flags |= TUB_ATTN; + + if (dsp->dstat & DEV_STAT_CHN_END) { + tubp->cswl = dsp->rescnt; + if ((dsp->dstat & DEV_STAT_DEV_END) == 0) + tubp->flags |= TUB_EXPECT_DE; + else + tubp->flags &= ~TUB_EXPECT_DE; + } else if (dsp->dstat & DEV_STAT_DEV_END) { + if ((tubp->flags & TUB_EXPECT_DE) == 0) + tubp->flags |= TUB_UNSOL_DE; + tubp->flags &= ~TUB_EXPECT_DE; + } + if (dsp->dstat & DEV_STAT_DEV_END) + tubp->flags &= ~TUB_WORKING; + + if ((tubp->flags & TUB_WORKING) == 0) + fs3270_sched_bh(tubp); +} + +/* + * process ioctl commands for the tube driver + */ +static int +fs3270_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) +{ + tub_t *tubp; + int rc = 0, flags; + + if ((tubp = INODE2TUB(ip)) == NULL) + return -ENODEV; + if ((rc = fs3270_wait(tubp, &flags))) { + TUBUNLOCK(tubp->irq, flags); + return rc; + } + + switch(cmd) { + case TUBICMD: tubp->icmd = arg; break; + case TUBOCMD: tubp->ocmd = arg; break; + case TUBGETI: put_user(tubp->icmd, (char *)arg); break; + case TUBGETO: put_user(tubp->ocmd, (char *)arg); break; + case TUBGETMOD: + if (copy_to_user((char *)arg, &tubp->tubiocb, + sizeof tubp->tubiocb)) + rc = -EFAULT; + break; + } + TUBUNLOCK(tubp->irq, flags); + return rc; +} + +/* + * process read commands for the tube driver + */ +static int +fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off) +{ + tub_t *tubp; + char *kp; + ccw1_t *cp; + int rc, flags; + + if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL) + return -ENODEV; + if ((rc = fs3270_wait(tubp, &flags)) != 0) { + TUBUNLOCK(tubp->irq, flags); + return rc; + } + + kp = kmalloc(len, GFP_KERNEL); + if (kp == NULL) { + TUBUNLOCK(tubp->irq, flags); + return -ENOMEM; + } + + cp = &tubp->rccw; + if (tubp->icmd == 0 && tubp->ocmd != 0) tubp->icmd = 6; + cp->cmd_code = tubp->icmd?:2; + cp->flags = CCW_FLAG_SLI; + cp->count = len; + cp->cda = virt_to_phys(kp); + tubp->flags |= TUB_RDPENDING; + TUBUNLOCK(tubp->irq, flags); + + if ((rc = fs3270_wait(tubp, &flags)) != 0) { + tubp->flags &= ~TUB_RDPENDING; + TUBUNLOCK(tubp->irq, flags); + kfree(kp); + return rc; + } + + len -= tubp->cswl; + TUBUNLOCK(tubp->irq, flags); + if (tubdebug & 1) + printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n", + tubp->minor, + *(int*)((int)kp + 0), + *(int*)((int)kp + 4), + *(int*)((int)kp + 8), + *(int*)((int)kp + 12)); + copy_to_user(dp, kp, len); + kfree(kp); + return len; +} + +/* + * process write commands for the tube driver + */ +static int +fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off) +{ + tub_t *tubp; + ccw1_t *cp; + int rc, flags; + void *kb; + + /* Locate the tube */ + if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL) + return -ENODEV; + + /* Copy data to write from user address space */ + if ((kb = kmalloc(len, GFP_KERNEL)) == NULL) + return -ENOMEM; + if (copy_from_user(kb, dp, len) != 0) { + kfree(kb); + return -EFAULT; + } + + /* Wait till tube's not working or signal is pending */ + if ((rc = fs3270_wait(tubp, &flags))) { + TUBUNLOCK(tubp->irq, flags); + kfree(kb); + return rc; + } + + /* Make CCW and start I/O. Back end will free buffer. */ + tubp->wbuf = kb; + cp = &tubp->wccw; + cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1; + cp->flags = CCW_FLAG_SLI; + cp->count = len; + cp->cda = virt_to_phys(tubp->wbuf); + fs3270_io(tubp, cp); + TUBUNLOCK(tubp->irq, flags); + return len; +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubio.h linux/drivers/s390/char/tubio.h --- v2.4.3/linux/drivers/s390/char/tubio.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubio.h Wed Apr 11 19:02:28 2001 @@ -0,0 +1,432 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubio.h -- All-Purpose header file + * + * + * + * + * + * Author: Richard Hitt + */ +#include <linux/config.h> + +#include <linux/module.h> +#include <linux/version.h> + +#include <linux/major.h> +#ifndef IBM_TTY3270_MAJOR +# define IBM_TTY3270_MAJOR 212 +#endif /* IBM_TTY3270_MAJOR */ +#ifndef IBM_FS3270_MAJOR +# define IBM_FS3270_MAJOR 213 +#endif /* IBM_FS3270_MAJOR */ + + +#include <linux/malloc.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <linux/console.h> +#include <linux/interrupt.h> +#include <asm/ebcdic.h> +#include <asm/uaccess.h> +#include <linux/proc_fs.h> + +#define TUB(x) (('3'<<8)|(x)) +#define TUBICMD TUB(3) +#define TUBOCMD TUB(4) +#define TUBGETI TUB(7) +#define TUBGETO TUB(8) +#define TUBSETMOD TUB(12) +#define TUBGETMOD TUB(13) +#define TIOPOLL TUB(32) +#define TIOPOKE TUB(33) +#define TIONPOKE TUB(34) +#define TIOTNORM TUB(35) + +/* Local Channel Commands */ +#define TC_WRITE 0x01 +#define TC_EWRITE 0x05 +#define TC_READMOD 0x06 +#define TC_EWRITEA 0x0d +#define TC_WRITESF 0x11 + +/* Buffer Control Orders */ +#define TO_SF 0x1d +#define TO_SBA 0x11 +#define TO_IC 0x13 +#define TO_PT 0x05 +#define TO_RA 0x3c +#define TO_SFE 0x29 +#define TO_EUA 0x12 +#define TO_MF 0x2c +#define TO_SA 0x28 + +/* Field Attribute Bytes */ +#define TF_INPUT 0x40 /* Visible input */ +#define TF_INPUTN 0x4c /* Invisible input */ +#define TF_INMDT 0xc1 /* Visible, Set-MDT */ +#define TF_LOG 0x60 +#define TF_STAT 0x60 + +/* Character Attribute Bytes */ +#define TAT_RESET 0x00 +#define TAT_FIELD 0xc0 +#define TAT_EXTHI 0x41 +#define TAT_COLOR 0x42 +#define TAT_CHARS 0x43 +#define TAT_TRANS 0x46 + +/* Reset value */ +#define TAR_RESET 0x00 + +/* Color values */ +#define TAC_BLUE 0xf1 +#define TAC_RED 0xf2 +#define TAC_PINK 0xf3 +#define TAC_GREEN 0xf4 +#define TAC_TURQ 0xf5 +#define TAC_YELLOW 0xf6 +#define TAC_WHITE 0xf7 +#define TAC_DEFAULT 0x00 + +/* Write Control Characters */ +#define TW_NONE 0x40 /* No particular action */ +#define TW_KR 0xc2 /* Keyboard restore */ +#define TW_PLUSALARM 0x04 /* Add this bit for alarm */ + +/* Attention-ID (AID) Characters */ +#define TA_CLEAR 0x6d +#define TA_PA2 0x6e +#define TA_ENTER 0x7d +/* more to come */ + +#define MIN(a, b) ((a) < (b)? (a): (b)) + +#define TUB_BUFADR(adr, cpp) \ + tty3270_tub_bufadr(tubp, adr, cpp) + +#define TUB_EBCASC(addr, nr) codepage_convert(tub_ebcasc, addr, nr) +#define TUB_ASCEBC(addr, nr) codepage_convert(tub_ascebc, addr, nr) + +/* + * + * General global values for the tube driver + * + */ +enum tubmode { + TBM_LN, /* Line mode */ + TBM_FS, /* Fullscreen mode */ + TBM_FSLN /* Line mode shelled out of fullscreen */ +}; +enum tubstat { /* normal-mode status */ + TBS_RUNNING, /* none of the following */ + TBS_MORE, /* timed "MORE..." in status */ + TBS_HOLD /* untimed "HOLDING" in status */ +}; +enum tubcmd { /* normal-mode actions to do */ + TBC_CONOPEN, /* Erase-write the console */ + TBC_OPEN, /* Open the tty screen */ + TBC_UPDATE, /* Add lines to the log, clear cmdline */ + TBC_UPDLOG, /* Add lines to log */ + TBC_KRUPDLOG, /* Add lines to log, reset kbd */ + TBC_CLEAR, /* Build screen from scratch */ + TBC_CLRUPDLOG, /* Do log & status, not cmdline */ + TBC_UPDSTAT, /* Do status update only */ + TBC_CLRINPUT, /* Clear input area only */ + TBC_UPDINPUT /* Update input area only */ +}; +enum tubwhat { /* echo what= proc actions */ + TW_BOGUS, /* Nothing at all */ + TW_CONFIG /* Output configuration info */ +}; + + + + + +#define TUBMAXMINS 256 +#define TUB_DEV MKDEV(IBM_FS3270_MAJ, 0) /* Generic /dev/3270/tub */ +#define _GEOM_ROWS 24 +#define _GEOM_COLS 80 +#define GEOM_ROWS (tubp->geom_rows) +#define GEOM_COLS (tubp->geom_cols) +#define GEOM_MAXROWS 127 +#define GEOM_MAXCOLS 132 +#define GEOM_INPLEN (GEOM_COLS * 2 - 20) +#define GEOM_MAXINPLEN (GEOM_MAXCOLS * 2 - 20) +#define GEOM_INPUT (GEOM_COLS * (GEOM_ROWS - 2) - 1) /* input atr posn */ +#define GEOM_STAT (GEOM_INPUT + 1 + GEOM_INPLEN) +#define GEOM_LOG (GEOM_COLS * GEOM_ROWS - 1) /* log atr posn */ +#define TS_RUNNING "Linux Running " +#define TS_MORE "Linux More... " +#define DEFAULT_SCROLLTIME 5 +#define TS_HOLD "Linux Holding " +/* data length used by tty3270_set_status_area: SBA (3), SF (2), data */ +#define TS_LENGTH (sizeof TS_RUNNING + 3 + 2) + +typedef struct { + int aid; /* What-to-do flags */ + char *string; /* Optional input string */ +} aid_t; +#define AIDENTRY(ch, tubp) (&((tubp)->tty_aid[(ch) & 0x3f])) + +/* For TUBGETMOD and TUBSETMOD. Should include. */ +typedef struct tubiocb { + short model; + short line_cnt; + short col_cnt; + short pf_cnt; + short re_cnt; + short map; +} tubiocb_t; + +/* Flags that go in int aid, above */ +#define TA_CLEARKEY 0x01 /* Key does hardware CLEAR */ +#define TA_SHORTREAD 0x02 /* Key does hardware shortread */ +/* If both are off, key does hardware Read Modified. */ +#define TA_DOENTER 0x04 /* Treat key like ENTER */ +#define TA_DOSTRING 0x08 /* Use string and ENTER */ +#define TA_DOSTRINGD 0x10 /* Display string & set MDT */ +#define TA_CLEARLOG 0x20 /* Make key cause clear of log */ + +/* + * Tube driver buffer control block + */ +typedef struct bcb_s { + char *bc_buf; /* Pointer to buffer */ + int bc_len; /* Length of buffer */ + int bc_cnt; /* Count of bytes buffered */ + int bc_wr; /* Posn to write next byte into */ + int bc_rd; /* Posn to read next byte from */ +} bcb_t; + +typedef struct tub_s { + int minor; + int irq; + int irqrc; + int devno; + int geom_rows; + int geom_cols; + tubiocb_t tubiocb; + int lnopen; + int fsopen; + int icmd; + int ocmd; + devstat_t devstat; + ccw1_t rccw; + ccw1_t wccw; + void *wbuf; + int cswl; + void (*intv)(struct tub_s *, devstat_t *); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + struct wait_queue *waitq; +#else + wait_queue_head_t waitq; +#endif + int dstat; + sense_t sense; + enum tubmode mode; + enum tubstat stat; + enum tubcmd cmd; + int flags; /* See below for values */ + struct tq_struct tqueue; + + /* Stuff for fs-driver support */ + pid_t fs_pid; /* Pid if TBM_FS */ + + + /* Stuff for tty-driver support */ + struct tty_struct *tty; + char tty_input[GEOM_MAXINPLEN]; /* tty input area */ + int tty_inattr; /* input-area field attribute */ +#define TTY_OUTPUT_SIZE 1024 + bcb_t tty_bcb; /* Output buffer control info */ + int tty_oucol; /* Kludge */ + int tty_nextlogx; /* next screen-log position */ + int tty_scrolltime; /* scrollforward wait time, sec */ + struct timer_list tty_stimer; /* timer for scrolltime */ + aid_t tty_aid[64]; /* Aid descriptors */ + int tty_aidinit; /* Boolean */ + int tty_showaidx; /* Last aid x to set_aid */ + int tty_14bitadr; /* 14-bit bufadrs okay */ +#define MAX_TTY_ESCA 24 /* Set-Attribute-Order array */ + char tty_esca[MAX_TTY_ESCA]; /* SA array */ + int tty_escx; /* Current index within it */ + + /* For command recall --- */ + char *(*tty_rclbufs)[]; /* Array of ptrs to recall bufs */ + int tty_rclk; /* Size of array tty_rclbufs */ + int tty_rclp; /* Index for most-recent cmd */ + int tty_rclb; /* Index for backscrolling */ + + /* Work area to contain the hardware write stream */ + char (*ttyscreen)[]; /* ptr to data stream area */ + int ttyscreenl; /* its length */ + ccw1_t ttyccw; +} tub_t; + +/* values for flags: */ +#define TUB_WORKING 0x0001 +#define TUB_BHPENDING 0x0002 +#define TUB_RDPENDING 0x0004 +#define TUB_ALARM 0x0008 +#define TUB_SCROLLTIMING 0x0010 +#define TUB_ATTN 0x0020 +#define TUB_IACTIVE 0x0040 +#define TUB_SIZED 0x0080 +#define TUB_EXPECT_DE 0x0100 +#define TUB_UNSOL_DE 0x0200 +#define TUB_OPEN_STET 0x0400 /* No screen clear on open */ +#define TUB_UE_BUSY 0x0800 + +#ifdef CONFIG_3270_CONSOLE +/* + * Extra stuff for 3270 console support + */ +#define S390_CONSOLE_DEV MKDEV(TTY_MAJOR, 64) +extern int tub3270_con_devno; +extern char (*tub3270_con_output)[]; +extern int tub3270_con_outputl; +extern int tub3270_con_ouwr; +extern int tub3270_con_oucount; +extern int tub3270_con_irq; +extern tub_t *tub3270_con_tubp; +extern struct tty_driver tty3270_con_driver; +#endif /* CONFIG_3270_CONSOLE */ + +extern int tubnummins; +extern tub_t *(*tubminors)[TUBMAXMINS]; +extern tub_t *(*(*tubirqs)[256])[256]; +extern unsigned char tub_ascebc[256]; +extern unsigned char tub_ebcasc[256]; +extern unsigned char tub_ebcgraf[64]; +extern int tubdebug; +extern int fs3270_major; +extern int tty3270_major; +extern int tty3270_proc_misc; +extern enum tubwhat tty3270_proc_what; + +#ifndef spin_trylock_irqsave +#define spin_trylock_irqsave(lock, flags) \ +({ \ + int success; \ + __save_flags(flags); \ + __cli(); \ + success = spin_trylock(lock); \ + if (success == 0) \ + __restore_flags(flags); \ + success; \ +}) +#endif /* if not spin_trylock_irqsave */ + +#ifndef s390irq_spin_trylock_irqsave +#define s390irq_spin_trylock_irqsave(irq, flags) \ + spin_trylock_irqsave(&(ioinfo[irq]->irq_lock), flags) +#endif /* if not s390irq_spin_trylock_irqsave */ + +#define TUBLOCK(irq, flags) \ + s390irq_spin_lock_irqsave(irq, flags) + +#define TUBTRYLOCK(irq, flags) \ + s390irq_spin_trylock_irqsave(irq, flags) + +#define TUBUNLOCK(irq, flags) \ + s390irq_spin_unlock_irqrestore(irq, flags) + +/* + * Find tub_t * given fullscreen device's irq (subchannel number) + */ +extern tub_t *tubfindbyirq(int); +#define IRQ2TUB(irq) tubfindbyirq(irq) +/* + * Find tub_t * given fullscreen device's inode pointer + * This algorithm takes into account /dev/3270/tub. + */ +#ifdef CONFIG_3270_CONSOLE +#define INODE2TUB(ip) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR((ip)->i_rdev); \ + if (minor == 0 && current->tty != NULL) { \ + if (tub3270_con_tubp != NULL && \ + current->tty->device == S390_CONSOLE_DEV) \ + minor = tub3270_con_tubp->minor; \ + else if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \ + minor = MINOR(current->tty->device); \ + } \ + if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#else /* not CONFIG_3270_CONSOLE */ +#define INODE2TUB(ip) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR((ip)->i_rdev); \ + if (minor == 0 && current->tty != NULL && \ + MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \ + minor = MINOR(current->tty->device); \ + if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#endif /* CONFIG_3270_CONSOLE or not */ +/* + * Find tub_t * given non-fullscreen (tty) device's tty_struct pointer + */ +#ifdef CONFIG_3270_CONSOLE +#define TTY2TUB(tty) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR(tty->device); \ + if (tty->device == S390_CONSOLE_DEV) \ + tubp = tub3270_con_tubp; \ + else if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#else /* if not CONFIG_3270_CONSOLE */ +#define TTY2TUB(tty) \ +({ \ + unsigned int minor; \ + tub_t *tubp = NULL; \ + minor = MINOR(tty->device); \ + if (minor <= tubnummins && minor > 0) \ + tubp = (*tubminors)[minor]; \ + tubp; \ +}) +#endif /* CONFIG_3270_CONSOLE or not */ + +extern void tub_inc_use_count(void); +extern void tub_dec_use_count(void); +extern int tub3270_movedata(bcb_t *, bcb_t *); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +extern int tubmakemin(int, dev_info_t *); +#else +extern int tubmakemin(int, s390_dev_info_t *); +#endif +extern int tub3270_con_copy(tub_t *); +extern int tty3270_rcl_init(tub_t *); +extern int tty3270_rcl_set(tub_t *, char *, int); +extern void tty3270_rcl_fini(tub_t *); +extern int tty3270_rcl_get(tub_t *, char *, int, int); +extern void tty3270_rcl_put(tub_t *, char *, int); +extern void tty3270_rcl_sync(tub_t *); +extern void tty3270_rcl_purge(tub_t *); +extern int tty3270_rcl_resize(tub_t *, int); +extern int tty3270_size(tub_t *, int *); +extern int tty3270_aid_init(tub_t *); +extern void tty3270_aid_fini(tub_t *); +extern void tty3270_aid_reinit(tub_t *); +extern int tty3270_aid_get(tub_t *, int, int *, char **); +extern int tty3270_aid_set(tub_t *, char *, int); +extern int tty3270_build(tub_t *); +extern void tty3270_scl_settimer(tub_t *); +extern void tty3270_scl_resettimer(tub_t *); +extern int tty3270_scl_set(tub_t *, char *, int); +extern int tty3270_scl_init(tub_t *tubp); +extern void tty3270_scl_fini(tub_t *tubp); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubtty.c linux/drivers/s390/char/tubtty.c --- v2.4.3/linux/drivers/s390/char/tubtty.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubtty.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,1001 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC + * + * tubtty.c -- Linemode tty driver + * + * + * + * + * + * Author: Richard Hitt + */ +#include <linux/config.h> +#include "tubio.h" + +/* Initialization & uninitialization for tubtty */ +int tty3270_init(void); +void tty3270_fini(void); + +/* Interface routines from the upper tty layer to the tty driver */ +static int tty3270_open(struct tty_struct *, struct file *); +static void tty3270_close(struct tty_struct *, struct file *); +static int tty3270_write(struct tty_struct *, int, + const unsigned char *, int); +static void tty3270_put_char(struct tty_struct *, unsigned char); +static void tty3270_flush_chars(struct tty_struct *); +static int tty3270_write_room(struct tty_struct *); +static int tty3270_chars_in_buffer(struct tty_struct *); +static int tty3270_ioctl(struct tty_struct *, struct file *, + unsigned int cmd, unsigned long arg); +static void tty3270_set_termios(struct tty_struct *, struct termios *); +static void tty3270_hangup(struct tty_struct *); +static void tty3270_flush_buffer(struct tty_struct *); +static int tty3270_read_proc(char *, char **, off_t, int, int *, void *); +static int tty3270_write_proc(struct file *, const char *, + unsigned long, void *); + +/* tty3270 utility functions */ +static void tty3270_bh(void *); + void tty3270_sched_bh(tub_t *); +static int tty3270_wait(tub_t *, int *); + void tty3270_int(tub_t *, devstat_t *); + int tty3270_try_logging(tub_t *); +static void tty3270_start_input(tub_t *); +static void tty3270_do_input(tub_t *); +static void tty3270_do_enter(tub_t *, char *, int); +static void tty3270_do_showi(tub_t *, char *, int); + int tty3270_io(tub_t *); +static int tty3270_show_tube(int, char *, int); + +int tty3270_major = -1; +char tty3270_major_string[16]; +struct tty_driver tty3270_driver; +int tty3270_refcount; +struct tty_struct *tty3270_table[TUBMAXMINS]; +struct termios *tty3270_termios[TUBMAXMINS]; +struct termios *tty3270_termios_locked[TUBMAXMINS]; +#ifdef CONFIG_3270_CONSOLE +int con3270_major = -1; +struct tty_driver con3270_driver; +int con3270_refcount; +struct tty_struct *con3270_table[1]; +struct termios *con3270_termios[1]; +struct termios *con3270_termios_locked[1]; +#endif /* CONFIG_3270_CONSOLE */ + +int tty3270_proc_index; +int tty3270_proc_data; +int tty3270_proc_misc; +enum tubwhat tty3270_proc_what; + +/* + * tty3270_init() -- Register the tty3270 driver + */ +int +tty3270_init(void) +{ + struct tty_driver *td = &tty3270_driver; + int rc; + + /* Initialize for tty driver */ + td->magic = TTY_DRIVER_MAGIC; + td->driver_name = "tty3270"; + td->name = "tty3270"; + td->major = IBM_TTY3270_MAJOR; + td->minor_start = 0; + td->num = TUBMAXMINS; + td->type = TTY_DRIVER_TYPE_SYSTEM; + td->subtype = SYSTEM_TYPE_TTY; + td->init_termios = tty_std_termios; + td->flags = TTY_DRIVER_RESET_TERMIOS; + td->refcount = &tty3270_refcount; + td->table = tty3270_table; + td->termios = tty3270_termios; + td->termios_locked = tty3270_termios_locked; + + td->open = tty3270_open; + td->close = tty3270_close; + td->write = tty3270_write; + td->put_char = tty3270_put_char; + td->flush_chars = tty3270_flush_chars; + td->write_room = tty3270_write_room; + td->chars_in_buffer = tty3270_chars_in_buffer; + td->ioctl = tty3270_ioctl; + td->ioctl = NULL; + td->set_termios = tty3270_set_termios; + td->throttle = NULL; + td->unthrottle = NULL; + td->stop = NULL; + td->start = NULL; + td->hangup = tty3270_hangup; + td->break_ctl = NULL; + td->flush_buffer = tty3270_flush_buffer; + td->set_ldisc = NULL; + td->wait_until_sent = NULL; + td->send_xchar = NULL; + td->read_proc = tty3270_read_proc; + td->write_proc = tty3270_write_proc; + + rc = tty_register_driver(td); + if (rc) { + printk(KERN_ERR "tty3270 registration failed with %d\n", rc); + } else { + tty3270_major = IBM_TTY3270_MAJOR; + sprintf(tty3270_major_string, "%d", tty3270_major); + if (td->proc_entry != NULL) + td->proc_entry->mode = S_IRUGO | S_IWUGO; + } +#ifdef CONFIG_3270_CONSOLE + tty3270_con_driver = *td; + td = &tty3270_con_driver; + td->driver_name = "con3270"; + td->name = "con3270"; + td->major = MAJOR(S390_CONSOLE_DEV); + td->minor_start = MINOR(S390_CONSOLE_DEV); + td->num = 1; + td->refcount = &con3270_refcount; + td->table = con3270_table; + td->termios = con3270_termios; + td->termios_locked = con3270_termios_locked; + + rc = tty_register_driver(td); + if (rc) { + printk(KERN_ERR "con3270 registration failed with %d\n", rc); + } else { + con3270_major = MAJOR(S390_CONSOLE_DEV); + if (td->proc_entry != NULL) + td->proc_entry->mode = S_IRUGO | S_IWUGO; + } +#endif /* if CONFIG_3270_CONSOLE */ + + return rc; +} + +/* + * tty3270_fini() -- Uninitialize linemode tubes + */ +void +tty3270_fini(void) +{ + if (tty3270_major != -1) { + tty_unregister_driver(&tty3270_driver); + tty3270_major = -1; + } +#ifdef CONFIG_3270_CONSOLE + if (con3270_major != -1) { + tty_unregister_driver(&con3270_driver); + con3270_major = -1; + } +#endif +} + +static int +tty3270_open(struct tty_struct *tty, struct file *filp) +{ + tub_t *tubp; + int flags; + int rc; + int cmd; + + if ((tubp = TTY2TUB(tty)) == NULL) { + return -ENODEV; + } + + tub_inc_use_count(); + if ((rc = tty3270_wait(tubp, &flags)) != 0) + goto do_fail; + if (tubp->lnopen > 0) { + tubp->lnopen++; + TUBUNLOCK(tubp->irq, flags); + return 0; + } + if (tubp->flags & TUB_OPEN_STET) { + cmd = TBC_UPDLOG; + } else { + cmd = TBC_OPEN; + tubp->flags &= ~TUB_SIZED; + } + if ((rc = tty3270_size(tubp, &flags)) != 0) + goto do_fail; + if ((rc = tty3270_rcl_init(tubp)) != 0) + goto do_fail; + if ((rc = tty3270_aid_init(tubp)) != 0) + goto do_fail; + if ((rc = tty3270_scl_init(tubp)) != 0) + goto do_fail; + tubp->mode = TBM_LN; + tubp->intv = tty3270_int; + tubp->tty = tty; + tubp->lnopen = 1; + tty->driver_data = tubp; + tty->winsize.ws_row = tubp->geom_rows; + tty->winsize.ws_col = tubp->geom_cols; + tubp->tty_inattr = TF_INPUT; + tubp->cmd = cmd; + tty3270_build(tubp); + TUBUNLOCK(tubp->irq, flags); + return 0; + +do_fail: + tty3270_scl_fini(tubp); + tty3270_aid_fini(tubp); + tty3270_rcl_fini(tubp); + TUBUNLOCK(tubp->irq, flags); + tub_dec_use_count(); + return rc; +} + +static void +tty3270_close(struct tty_struct *tty, struct file *filp) +{ + tub_t *tubp; + int flags; + + if ((tubp = tty->driver_data) == NULL) + return; + + tty3270_wait(tubp, &flags); + if (--tubp->lnopen > 0) + goto do_return; + tubp->tty = NULL; + tty->driver_data = NULL; + tty3270_aid_fini(tubp); + tty3270_rcl_fini(tubp); + tty3270_scl_fini(tubp); +do_return: + tub_dec_use_count(); + TUBUNLOCK(tubp->irq, flags); +} + +static int +tty3270_write(struct tty_struct *tty, int fromuser, + const unsigned char *buf, int count) +{ + tub_t *tubp; + int flags; + bcb_t obcb; + int rc = 0; + + if ((tubp = tty->driver_data) == NULL) + return -1; + +#ifdef CONFIG_3270_CONSOLE + if (tub3270_con_tubp == tubp) + tub3270_con_copy(tubp); +#endif /* CONFIG_3270_CONSOLE */ + + obcb.bc_buf = (char *)buf; + obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count; + obcb.bc_rd = 0; + + TUBLOCK(tubp->irq, flags); + rc = tub3270_movedata(&obcb, &tubp->tty_bcb); + tty3270_try_logging(tubp); + TUBUNLOCK(tubp->irq, flags); + return rc; +} + +static void +tty3270_put_char(struct tty_struct *tty, unsigned char ch) +{ + int flags; + tub_t *tubp; + bcb_t *ob; + + if ((tubp = tty->driver_data) == NULL) + return; + + TUBLOCK(tubp->irq, flags); + ob = &tubp->tty_bcb; + if (ob->bc_cnt < ob->bc_len) { + ob->bc_buf[ob->bc_wr++] = ch; + if (ob->bc_wr == ob->bc_len) + ob->bc_wr = 0; + ob->bc_cnt++; + } + tty3270_try_logging(tubp); + TUBUNLOCK(tubp->irq, flags); +} + +static void +tty3270_flush_chars(struct tty_struct *tty) +{ + tub_t *tubp; + int flags; + + if ((tubp = tty->driver_data) == NULL) + return; + + TUBLOCK(tubp->irq, flags); + tty3270_try_logging(tubp); + TUBUNLOCK(tubp->irq, flags); +} + +static int +tty3270_write_room(struct tty_struct *tty) +{ + tub_t *tubp; + bcb_t *ob; + + if ((tubp = tty->driver_data) == NULL) + return -1; + + ob = &tubp->tty_bcb; + return ob->bc_len - ob->bc_cnt; +} + +static int +tty3270_chars_in_buffer(struct tty_struct *tty) +{ + tub_t *tubp; + bcb_t *ob; + + if ((tubp = tty->driver_data) == NULL) + return -1; + + ob = &tubp->tty_bcb; + return ob->bc_cnt; +} + +static int +tty3270_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + tub_t *tubp; + int flags; + int ret = 0; + struct termios termios; + + if ((tubp = tty->driver_data) == NULL) + return -ENODEV; + + TUBLOCK(tubp->irq, flags); + if (tty->flags * (1 << TTY_IO_ERROR)) { + ret = -EIO; + goto do_return; + } + switch(cmd) { + case TCGETS: + ret = -ENOIOCTLCMD; + goto do_return; + case TCFLSH: /* arg: 2 or 0 */ + ret = -ENOIOCTLCMD; + goto do_return; + case TCSETSF: + if (user_termios_to_kernel_termios(&termios, + (struct termios *)arg)) { + ret = -EFAULT; + goto do_return; + } + ret = -ENOIOCTLCMD; + goto do_return; + case TCGETA: + ret = -ENOIOCTLCMD; + goto do_return; + case TCSETA: + if (user_termio_to_kernel_termios(&termios, + (struct termio *)arg)) { + ret = -EFAULT; + goto do_return; + } + ret = -ENOIOCTLCMD; + goto do_return; + default: + ret = -ENOIOCTLCMD; + break; + } + +do_return: + TUBUNLOCK(tubp->irq, flags); + return ret; +} + +static void +tty3270_set_termios(struct tty_struct *tty, struct termios *old) +{ + tub_t *tubp; + int flags; + int new; + + if ((tubp = tty->driver_data) == NULL) + return; + + if (tty3270_wait(tubp, &flags) != 0) { + TUBUNLOCK(tubp->irq, flags); + return; + } + new = L_ICANON(tty)? L_ECHO(tty)? TF_INPUT: TF_INPUTN: + tubp->tty_inattr; + if (new != tubp->tty_inattr) { + tubp->tty_inattr = new; + tubp->cmd = TBC_CLRINPUT; + tty3270_build(tubp); + } + + TUBUNLOCK(tubp->irq, flags); +} + +static void +tty3270_flush_buffer(struct tty_struct *tty) +{ + tub_t *tubp; + bcb_t *ob; + int flags; + + if ((tubp = tty->driver_data) == NULL) + return; + + if (tubp->mode == TBM_FS && tubp->fs_pid != 0) { + kill_proc(tubp->fs_pid, SIGHUP, 1); + } + + if ((tubp->flags & TUB_OPEN_STET) == 0) { + ob = &tubp->tty_bcb; + TUBLOCK(tubp->irq, flags); + ob->bc_rd = 0; + ob->bc_wr = 0; + ob->bc_cnt = 0; + TUBUNLOCK(tubp->irq, flags); + } + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +static int +tty3270_read_proc(char *buf, char **start, off_t off, int count, + int *eof, void *data) +{ + tub_t *tubp; + int begin = 0; + int i; + int rc; + int len = 0; + char *majstr; + + if (tty3270_proc_what == TW_CONFIG) { + /* + * Describe the 3270 configuration in ascii lines. + * Line 1: 0 <fsmajor> 0 + * Console line: <devnum> CONSOLE <minor> + * Other lines: <devnum> <ttymajor> <minor> + */ + len += sprintf(buf + len, "0 %d 0\n", fs3270_major); + for (i = 1; i <= tubnummins; i++) { + tubp = (*tubminors)[i]; + majstr = tty3270_major_string; +#ifdef CONFIG_3270_CONSOLE + if (tubp == tub3270_con_tubp) + majstr = "CONSOLE"; +#endif /* CONFIG_3270_CONSOLE */ + len += sprintf(buf + len, "%.3x %s %d\n", + tubp->devno, majstr, i); + if (begin + len > off + count) + break; + if (begin + len < off) { + begin += len; + len = 0; + } + } + if (i > tubnummins) + *eof = 1; + if (off >= begin + len) { + rc = 0; + } else { + *start = buf + off - begin; + rc = MIN(count, begin + len - off); + } + if (*eof && rc == 0) + tty3270_proc_what = TW_BOGUS; + return rc; + } + + len += sprintf(buf, "There are %d devices. fs major is %d, " + "tty major is %d.\n", tubnummins, fs3270_major, + tty3270_major); + len += sprintf(buf+len, " index=%d data=%d misc=%d\n", + tty3270_proc_index, + tty3270_proc_data, + tty3270_proc_misc); + + /* + * Display info for the tube with minor nr in index + */ + len += tty3270_show_tube(tty3270_proc_index, buf+len, count-len); + + *eof = 1; + if (off >= begin + len) + return 0; + *start = buf + off - begin; + return MIN(count, begin + len - off); +} + +static int +tty3270_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char mybuf[GEOM_MAXINPLEN]; + int mycount; + tub_t *tubp; + struct tty_struct *tty; + kdev_t device; + int rc; + + mycount = MIN(count, sizeof mybuf - 1); + if (copy_from_user(mybuf, buffer, mycount) != 0) + return -EFAULT; + mybuf[mycount] = '\0'; + + /* + * User-mode settings affect only the current tty --- + */ + tubp = NULL; + tty = current->tty; + device = tty? tty->device: 0; + if (device) { + if (MAJOR(device) == IBM_TTY3270_MAJOR) + tubp = (*tubminors)[MINOR(device)]; +#ifdef CONFIG_3270_CONSOLE + if (device == S390_CONSOLE_DEV) + tubp = tub3270_con_tubp; +#endif /* CONFIG_3270_CONSOLE */ + } + if (tubp) { + if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1))) + return rc > 0? count: rc; + if ((rc = tty3270_rcl_set(tubp, mybuf, mycount + 1))) + return rc > 0? count: rc; + if ((rc = tty3270_scl_set(tubp, mybuf, mycount + 1))) + return rc > 0? count: rc; + } + + /* + * Superuser-mode settings affect the driver overall --- + */ + if (!suser()) { + return -EPERM; + } else if (strncmp(mybuf, "index=", 6) == 0) { + tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0); + return count; + } else if (strncmp(mybuf, "data=", 5) == 0) { + tty3270_proc_data = simple_strtoul(mybuf + 5, 0, 0); + return count; + } else if (strncmp(mybuf, "misc=", 5) == 0) { + tty3270_proc_misc = simple_strtoul(mybuf + 5, 0, 0); + return count; + } else if (strncmp(mybuf, "what=", 5) == 0) { + if (strcmp(mybuf+5, "bogus") == 0) + tty3270_proc_what = 0; + else if (strncmp(mybuf+5, "config", 6) == 0) + tty3270_proc_what = TW_CONFIG; + return count; + } else { + return -EINVAL; + } +} + +static void +tty3270_hangup(struct tty_struct *tty) +{ + tub_t *tubp; + extern void fs3270_release(tub_t *); + + if ((tubp = tty->driver_data) == NULL) + return; + tty3270_rcl_purge(tubp); + tty3270_aid_reinit(tubp); + fs3270_release(tubp); +} + + +/* + * tty3270_bh(tubp) -- Perform back-half processing + */ +static void +tty3270_bh(void *data) +{ + int flags; + tub_t *tubp; + struct tty_struct *tty; + + tubp = data; + TUBLOCK(tubp->irq, flags); + tubp->flags &= ~TUB_BHPENDING; + tty = tubp->tty; + + if (tubp->flags & TUB_UNSOL_DE) { + tubp->flags &= ~TUB_UNSOL_DE; + if (tty != NULL) { + tty_hangup(tty); + wake_up_interruptible(&tubp->waitq); + goto do_unlock; + } + } + + if (tubp->flags & TUB_IACTIVE) { /* If read ended, */ + tty3270_do_input(tubp); + tubp->flags &= ~TUB_IACTIVE; + } + + if ((tubp->flags & TUB_WORKING) == 0) { + if (tubp->flags & TUB_ATTN) { + tty3270_start_input(tubp); + tubp->flags &= ~TUB_ATTN; + } else if (tty3270_try_logging(tubp) == 0) { + wake_up_interruptible(&tubp->waitq); + } + } + + if (tty != NULL) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup != NULL) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +do_unlock: + TUBUNLOCK(tubp->irq, flags); +} + +/* + * tty3270_sched_bh(tubp) -- Schedule the back half + * Irq lock must be held on entry and remains held on exit. + */ +void +tty3270_sched_bh(tub_t *tubp) +{ + if (tubp->flags & TUB_BHPENDING) + return; + tubp->flags |= TUB_BHPENDING; + tubp->tqueue.routine = tty3270_bh; + tubp->tqueue.data = tubp; + queue_task(&tubp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * tty3270_io() -- Perform line-mode reads and writes here + */ +int +tty3270_io(tub_t *tubp) +{ + int rc; + ccw1_t *ccwp; + + tubp->flags |= TUB_WORKING; + tubp->dstat = 0; + ccwp = &tubp->ttyccw; + + rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0); + return rc; +} + +/* + * tty3270_wait(tubp) -- Wait until TUB_WORKING is off + * On entry the lock must not be held; on exit it is held. + */ +static int +tty3270_wait(tub_t *tubp, int *flags) +{ + DECLARE_WAITQUEUE(wait, current); + + TUBLOCK(tubp->irq, *flags); + add_wait_queue(&tubp->waitq, &wait); + while (!signal_pending(current) && + (tubp->flags & TUB_WORKING) != 0) { + current->state = TASK_INTERRUPTIBLE; + TUBUNLOCK(tubp->irq, *flags); + schedule(); + current->state = TASK_RUNNING; + TUBLOCK(tubp->irq, *flags); + } + remove_wait_queue(&tubp->waitq, &wait); + return signal_pending(current)? -ERESTARTSYS: 0; +} + +void +tty3270_int(tub_t *tubp, devstat_t *dsp) +{ +#define DEV_UE_BUSY \ + (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP) +#define DEV_NOT_WORKING \ + (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK) + + tubp->dstat = dsp->dstat; + + /* Handle CE-DE-UE and subsequent UDE */ + if (dsp->dstat == DEV_UE_BUSY) { + tubp->flags |= TUB_UE_BUSY; + return; + } else if (tubp->flags & TUB_UE_BUSY) { + tubp->flags &= ~TUB_UE_BUSY; + if (dsp->dstat == DEV_STAT_DEV_END && + (tubp->flags & TUB_WORKING) != 0) { + tty3270_io(tubp); + return; + } + } + + /* Handle ATTN */ + if (dsp->dstat & DEV_STAT_ATTENTION) + tubp->flags |= TUB_ATTN; + + if (dsp->dstat & DEV_STAT_CHN_END) { + tubp->cswl = dsp->rescnt; + if ((dsp->dstat & DEV_STAT_DEV_END) == 0) + tubp->flags |= TUB_EXPECT_DE; + else + tubp->flags &= ~TUB_EXPECT_DE; + } else if (dsp->dstat & DEV_STAT_DEV_END) { + if ((tubp->flags & TUB_EXPECT_DE) == 0) + tubp->flags |= TUB_UNSOL_DE; + tubp->flags &= ~TUB_EXPECT_DE; + } + if (dsp->dstat & DEV_NOT_WORKING) + tubp->flags &= ~TUB_WORKING; + if (dsp->dstat & DEV_STAT_UNIT_CHECK) + tubp->sense = dsp->ii.sense; + if ((tubp->flags & TUB_WORKING) == 0) + tty3270_sched_bh(tubp); +} + +/* + * tty3270_refresh(), called by fs3270_close() when tubp->fsopen == 0. + * On entry, lock is held. + */ +void +tty3270_refresh(tub_t *tubp) +{ + if (tubp->lnopen) { + tubp->mode = TBM_LN; + tubp->intv = tty3270_int; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_UPDATE; + tty3270_build(tubp); + } +} + +int +tty3270_try_logging(tub_t *tubp) +{ + if (tubp->flags & TUB_WORKING) + return 0; + if (tubp->mode == TBM_FS) + return 0; + if (tubp->stat == TBS_HOLD) + return 0; + if (tubp->stat == TBS_MORE) + return 0; +#ifdef CONFIG_3270_CONSOLE + if (tub3270_con_tubp == tubp) + tub3270_con_copy(tubp); +#endif /* CONFIG_3270_CONSOLE */ + if (tubp->tty_bcb.bc_cnt == 0) + return 0; + if (tubp->intv != tty3270_int) + return 0; + tubp->cmd = TBC_UPDLOG; + return tty3270_build(tubp); +} + +/* tty3270 utility functions */ + +static void +tty3270_start_input(tub_t *tubp) +{ + tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input); + tubp->ttyccw.cmd_code = TC_READMOD; + tubp->ttyccw.count = GEOM_INPLEN; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tty3270_io(tubp); + tubp->flags |= TUB_IACTIVE; +} + +static void +tty3270_do_input(tub_t *tubp) +{ + int count; + char *in; + int aidflags; + char *aidstring; + + count = GEOM_INPLEN - tubp->cswl; + in = tubp->tty_input; + tty3270_aid_get(tubp, in[0], &aidflags, &aidstring); + + if (aidflags & TA_CLEARKEY) { + tubp->stat = TBS_RUNNING; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_UPDATE; + } else if (aidflags & TA_CLEARLOG) { + tubp->stat = TBS_RUNNING; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_CLRUPDLOG; + } else if (aidflags & TA_DOENTER) { + if (count <= 6) { + switch(tubp->stat) { + case TBS_MORE: + tubp->stat = TBS_HOLD; + tty3270_scl_resettimer(tubp); + break; + case TBS_HOLD: + tubp->stat = TBS_MORE; + tty3270_scl_settimer(tubp); + break; + case TBS_RUNNING: + tty3270_do_enter(tubp, in + 6, 0); + break; + } + tubp->cmd = TBC_UPDSTAT; + goto do_build; + } + in += 6; + count -= 6; + TUB_EBCASC(in, count); + tubp->cmd = TBC_CLRINPUT; + tty3270_do_enter(tubp, in, count); + } else if ((aidflags & TA_DOSTRING) != 0 && aidstring != NULL) { + tubp->cmd = TBC_KRUPDLOG; + tty3270_do_enter(tubp, aidstring, strlen(aidstring)); + } else if ((aidflags & TA_DOSTRINGD) != 0 && aidstring != NULL) { + tty3270_do_showi(tubp, aidstring, strlen(aidstring)); + tubp->cmd = TBC_UPDINPUT; + } else { + if (in[0] != 0x60) + tubp->flags |= TUB_ALARM; + tubp->cmd = TBC_KRUPDLOG; + } +do_build: + tty3270_build(tubp); +} + +static void +tty3270_do_enter(tub_t *tubp, char *cp, int count) +{ + struct tty_struct *tty; + int func = -1; + + if ((tty = tubp->tty) == NULL) + return; + if (count < 0) + return; + if (count == 2 && (cp[0] == '^' || cp[0] == '\252')) { + switch(cp[1]) { + case 'c': case 'C': + func = INTR_CHAR(tty); + break; + case 'd': case 'D': + func = EOF_CHAR(tty); + break; + case 'z': case 'Z': + func = SUSP_CHAR(tty); + break; + } + } else if (count == 2 && cp[0] == 0x1b) { /* if ESC */ + int inc = 0; + char buf[GEOM_INPLEN + 1]; + int len; + + switch(cp[1]) { + case 'k': case 'K': + inc = -1; + break; + case 'j': case 'J': + inc = 1; + break; + } + if (inc == 0) + goto not_rcl; + len = tty3270_rcl_get(tubp, buf, sizeof buf, inc); + if (len == 0) { + tubp->flags |= TUB_ALARM; + return; + } + tty3270_do_showi(tubp, buf, len); + tubp->cmd = TBC_UPDINPUT; + return; + } +not_rcl: + if (func != -1) { + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = func; + tty->flip.count++; + } else { + tty3270_rcl_put(tubp, cp, count); + memcpy(tty->flip.char_buf_ptr, cp, count); + /* Add newline unless line ends with "^n" */ + if (count < 2 || cp[count - 1] != 'n' || + (cp[count - 2] != '^' && cp[count - 2] != '\252')) { + tty->flip.char_buf_ptr[count] = '\n'; + count++; + } else { + count -= 2; /* Lop trailing "^n" from text */ + } + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); + tty->flip.char_buf_ptr += count; + tty->flip.flag_buf_ptr += count; + tty->flip.count += count; + } + tty_flip_buffer_push(tty); +} + +static void +tty3270_do_showi(tub_t *tubp, char *cp, int cl) +{ + if (cl > GEOM_INPLEN) + cl = GEOM_INPLEN; + memset(tubp->tty_input, 0, GEOM_INPLEN); + memcpy(tubp->tty_input, cp, cl); + TUB_ASCEBC(tubp->tty_input, cl); +} + + + +/* Debugging routine */ +static int +tty3270_show_tube(int minor, char *buf, int count) +{ + tub_t *tubp; + struct tty_struct *tty; + struct termios *mp; + int len; + +/*012345678901234567890123456789012345678901234567890123456789 */ +/*Info for tub_t[dd] at xxxxxxxx: */ +/* geom: rows=dd cols=dd model=d */ +/* lnopen=dd fsopen=dd waitq=xxxxxxxx */ +/* dstat=xx mode=dd stat=dd flags=xxxx */ +/* oucount=dddd ourd=ddddd ouwr=ddddd nextlogx=ddddd */ +/* tty=xxxxxxxx */ +/* write_wait=xxxxxxxx read_wait=xxxxxxxx */ +/* iflag=xxxxxxxx oflag=xxxxxxxx cflag=xxxxxxxx lflag=xxxxxxxx */ + + if (minor < 0 || minor > tubnummins || + (tubp = (*tubminors)[minor]) == NULL) + return sprintf(buf, "No tube at index=%d\n", minor); + + tty = tubp->tty; + len = 0; + + len += sprintf(buf+len, +"Info for tub_t[%d] at %.8x:\n", + minor, (int)tubp); + + len += sprintf(buf+len, "inattr is at %.8x\n", + (int)&tubp->tty_inattr); + + + len += sprintf(buf+len, +" geom: rows=%.2d cols=%.2d model=%.1d\n", + tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model); + + len += sprintf(buf+len, +" lnopen=%-2d fsopen=%-2d waitq=%.8x\n", + tubp->lnopen, tubp->fsopen, (int)&tubp->waitq); + + len += sprintf(buf+len, +" dstat=%.2x mode=%-2d stat=%-2d flags=%-4x\n", + tubp->dstat, tubp->mode, tubp->stat, tubp->flags); + +#ifdef RBH_FIXTHIS + len += sprintf(buf+len, +" oucount=%-4d ourd=%-5d ouwr=%-5d nextlogx=%-5d\n", + tubp->tty_oucount, tubp->tty_ourd, tubp->tty_ouwr, + tubp->tty_nextlogx); +#endif + + len += sprintf(buf+len, +" tty=%.8x\n", + (int)tubp->tty); + + if (tty) len += sprintf(buf+len, +" write_wait=%.8x read_wait=%.8x\n", + (int)&tty->write_wait, (int)&tty->read_wait); + + if (tty && ((mp = tty->termios))) len += sprintf(buf+len, +" iflag=%.8x oflag=%.8x cflag=%.8x lflag=%.8x\n", + mp->c_iflag, mp->c_oflag, mp->c_cflag, mp->c_lflag); + + + return len; +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttyaid.c linux/drivers/s390/char/tubttyaid.c --- v2.4.3/linux/drivers/s390/char/tubttyaid.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubttyaid.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,205 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttyaid.c -- Linemode Attention-ID functionality + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + +#define PA1_STR "^C" +#define PF3_STR "^D" +#define PF9_STR "\033j" +#define PF10_STR "\033k" +#define PF11_STR "\033j" +/* other AID-key default strings */ + +aid_t aidtab[64] = { +/* 00 */ { 0, 0 }, +/* C1 = PF13 */ { TA_DOSTRING, 0 }, +/* C2 = PF14 */ { TA_DOSTRING, 0 }, +/* C3 = PF15 */ { TA_DOSTRING, 0 }, +/* C4 = PF16 */ { TA_DOSTRING, 0 }, +/* C5 = PF17 */ { TA_DOSTRING, 0 }, +/* C6 = PF18 */ { TA_DOSTRING, 0 }, +/* C7 = PF19 */ { TA_DOSTRING, 0 }, +/* C8 = PF20 */ { TA_DOSTRING, 0 }, +/* C9 = PF21 */ { TA_DOSTRING, 0 }, +/* 4A = PF22 */ { TA_DOSTRING, 0 }, +/* 4B = PF23 */ { TA_DOSTRING, 0 }, +/* 4C = PF24 */ { TA_DOSTRING, 0 }, +/* 0D */ { 0, 0 }, +/* 0E */ { 0, 0 }, +/* 0F */ { 0, 0 }, +/* 10 */ { 0, 0 }, +/* 11 */ { 0, 0 }, +/* 12 */ { 0, 0 }, +/* 13 */ { 0, 0 }, +/* 14 */ { 0, 0 }, +/* 15 */ { 0, 0 }, +/* 16 */ { 0, 0 }, +/* 17 */ { 0, 0 }, +/* 18 */ { 0, 0 }, +/* 19 */ { 0, 0 }, +/* 1A */ { 0, 0 }, +/* 1B */ { 0, 0 }, +/* 1C */ { 0, 0 }, +/* 1D */ { 0, 0 }, +/* 1E */ { 0, 0 }, +/* 1F */ { 0, 0 }, +/* 60 = NoAID */ { 0, 0 }, +/* 21 */ { 0, 0 }, +/* 22 */ { 0, 0 }, +/* 23 */ { 0, 0 }, +/* 24 */ { 0, 0 }, +/* 25 */ { 0, 0 }, +/* E6 = OpRdr */ { 0, 0 }, +/* E7 = MSRdr */ { 0, 0 }, +/* E8 = NoAID */ { 0, 0 }, +/* 29 */ { 0, 0 }, +/* 2A */ { 0, 0 }, +/* 6B = PA3 */ { TA_SHORTREAD, 0 }, +/* 6C = PA1 */ { TA_SHORTREAD | TA_DOSTRING, PA1_STR }, +/* 6D = CLEAR */ { TA_SHORTREAD | TA_CLEARKEY, 0 }, +/* 6E = PA2 */ { TA_SHORTREAD | TA_CLEARLOG, 0 }, +/* 2F */ { 0, 0 }, +/* F0 = TstRq */ { 0, 0 }, +/* F1 = PF1 */ { TA_DOSTRING, 0 }, +/* F2 = PF2 */ { TA_DOSTRING, 0 }, +/* F3 = PF3 */ { TA_DOSTRING, PF3_STR }, +/* F4 = PF4 */ { TA_DOSTRING, 0 }, +/* F5 = PF5 */ { TA_DOSTRING, 0 }, +/* F6 = PF6 */ { TA_DOSTRING, 0 }, +/* F7 = PF7 */ { TA_DOSTRING, 0 }, +/* F8 = PF8 */ { TA_DOSTRING, 0 }, +/* F9 = PF9 */ { TA_DOSTRING, PF9_STR }, +/* 7A = PF10 */ { TA_DOSTRING, PF10_STR }, +/* 7B = PF11 */ { TA_DOSTRING, PF11_STR }, +/* 7C = PF12 */ { TA_DOSTRING, 0 }, +/* 7D = ENTER */ { TA_DOENTER, 0 }, +/* 7E = Pen */ { 0, 0 }, +/* 3F */ { 0, 0 }, +}; + +int +tty3270_aid_init(tub_t *tubp) +{ + memcpy(tubp->tty_aid, aidtab, sizeof aidtab); + tubp->tty_aidinit = 1; + return 0; +} + +void +tty3270_aid_fini(tub_t *tubp) +{ + int i; + char *sp; + + if (tubp->tty_aidinit == 0) + return; + for (i = 0; i < 64; i++) { + if ((sp = tubp->tty_aid[i].string) == NULL) + continue; + if (sp == aidtab[i].string) + continue; + kfree(sp); + } + tubp->tty_aidinit = 0; +} + +void +tty3270_aid_reinit(tub_t *tubp) +{ + tty3270_aid_fini(tubp); + tty3270_aid_init(tubp); +} + +int +tty3270_aid_get(tub_t *tubp, int aid, int *aidflags, char **aidstring) +{ + aid_t *ap; + + ap = AIDENTRY(aid, tubp); + *aidflags = ap->aid; + *aidstring = ap->string; + return 0; +} + +/* + * tty3270_aid_set() -- write_proc extension + * Parse written string as an AID name. Return 0 if it's not. + * Otherwise absorb the string and return count or -error. + */ +int +tty3270_aid_set(tub_t *tubp, char *buf, int count) +{ + char name[8]; + char *sp; + int aidn, aidx; + aid_t *ap; + int len; + char *pfp; + + if (tubp->tty_aidinit == 0) + return 0; + if (count < 3) /* If AID-key name too short */ + return 0; + name[0] = buf[0] < 0x60? buf[0]: (buf[0] & 0x5f); + name[1] = buf[1] < 0x60? buf[1]: (buf[1] & 0x5f); + if (name[0] == 'P' && name[1] == 'F') { + aidn = simple_strtoul(buf+2, &sp, 10); + if (aidn < 1 || aidn > 24) + return 0; + aidx = aidn > 12? aidn - 12: aidn + 0x30; + ap = &tubp->tty_aid[aidx]; + } else if (name[0] == 'P' && name[1] == 'A') { + aidn = simple_strtoul(buf+2, &sp, 10); + if (aidn < 1 || aidn > 3) + return 0; + switch(aidn) { + case 1: aidx = 0x2c; break; + case 2: aidx = 0x2e; break; + case 3: aidx = 0x2b; break; + default: aidx = 0; break; + } + ap = &tubp->tty_aid[aidx]; + } else { + return 0; + } + + if (*sp == '\0') { + tubp->tty_showaidx = ap - tubp->tty_aid; + return count; + } else if (*sp == '=') { + len = strlen(++sp); + if (len == 0) { + if (ap->string != NULL && + ap->string != aidtab[aidx].string) + kfree(ap->string); + ap->string = aidtab[aidx].string; + ap->aid = aidtab[aidx].aid; + return count; + } + if ((pfp = kmalloc(len + 1, GFP_KERNEL)) == NULL) + return -ENOMEM; + if (ap->string != NULL && + ap->string != aidtab[aidx].string) + kfree(ap->string); + if (sp[len - 1] == '\n') { + ap->aid = TA_DOSTRING; + sp[len - 1] = '\0'; + len--; + } else { + ap->aid = TA_DOSTRINGD; + } + memcpy(pfp, sp, len + 1); + ap->string = pfp; + return count; + } else { + return -EINVAL; + } +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttybld.c linux/drivers/s390/char/tubttybld.c --- v2.4.3/linux/drivers/s390/char/tubttybld.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubttybld.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,448 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttybld.c -- Linemode tty driver screen-building functions + * + * + * + * + * + * Author: Richard Hitt + */ + +#include "tubio.h" + +extern int tty3270_io(tub_t *); +static void tty3270_set_status_area(tub_t *, char **); +static int tty3270_next_char(tub_t *); +static void tty3270_update_log_area(tub_t *, char **); +static void tty3270_update_log_area_esc(tub_t *, char **); +static void tty3270_clear_log_area(tub_t *, char **); +static void tty3270_tub_bufadr(tub_t *, int, char **); + +/* + * tty3270_clear_log_area(tub_t *tubp, char **cpp) + */ +static void +tty3270_clear_log_area(tub_t *tubp, char **cpp) +{ + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_LOG, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = TF_LOG; + *(*cpp)++ = TO_RA; + TUB_BUFADR(GEOM_INPUT, cpp); + *(*cpp)++ = '\0'; + tubp->tty_oucol = tubp->tty_nextlogx = 0; +} + +static void +tty3270_update_log_area(tub_t *tubp, char **cpp) +{ + int lastx = GEOM_INPUT; + int c; + int next, fill, i; + int sba_needed = 1; + char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH]; + + /* Place characters */ + while (tubp->tty_bcb.bc_cnt != 0) { + if (tubp->tty_nextlogx >= lastx) { + if (sba_needed == 0 || tubp->stat == TBS_RUNNING) { + tubp->stat = TBS_MORE; + tty3270_set_status_area(tubp, cpp); + tty3270_scl_settimer(tubp); + } + break; + } + + /* Check for room for another char + possible ESCs */ + if (&(*cpp)[tubp->tty_escx + 1] >= overrun) + break; + + /* Fetch a character */ + if ((c = tty3270_next_char(tubp)) == -1) + break; + + /* Add a Set-Buffer-Address Order if we haven't */ + if (sba_needed) { + sba_needed = 0; + *(*cpp)++ = TO_SBA; + TUB_BUFADR(tubp->tty_nextlogx, cpp); + } + + switch(c) { + default: + if (c < ' ') /* Blank it if we don't know it */ + c = ' '; + for (i = 0; i < tubp->tty_escx; i++) + *(*cpp)++ = tubp->tty_esca[i]; + tubp->tty_escx = 0; + *(*cpp)++ = tub_ascebc[(int)c]; + tubp->tty_nextlogx++; + tubp->tty_oucol++; + break; + case 0x1b: /* ESC */ + tty3270_update_log_area_esc(tubp, cpp); + break; + case '\r': + break; /* completely ignore 0x0d = CR. */ + case '\n': + if (tubp->tty_oucol == GEOM_COLS) { + tubp->tty_oucol = 0; + break; + } + next = (tubp->tty_nextlogx + GEOM_COLS) / + GEOM_COLS * GEOM_COLS; + next = MIN(next, lastx); + fill = next - tubp->tty_nextlogx; + if (fill < 5) { + for (i = 0; i < fill; i++) + *(*cpp)++ = tub_ascebc[' ']; + } else { + *(*cpp)++ = TO_RA; + TUB_BUFADR(next, cpp); + *(*cpp)++ = tub_ascebc[' ']; + } + tubp->tty_nextlogx = next; + tubp->tty_oucol = 0; + break; + case '\t': + fill = (tubp->tty_nextlogx % GEOM_COLS) % 8; + for (; fill < 8; fill++) { + if (tubp->tty_nextlogx >= lastx) + break; + *(*cpp)++ = tub_ascebc[' ']; + tubp->tty_nextlogx++; + tubp->tty_oucol++; + } + break; + case '\a': + tubp->flags |= TUB_ALARM; + break; + case '\f': + tty3270_clear_log_area(tubp, cpp); + break; + } + } +} + +#define NUMQUANT 8 +static void +tty3270_update_log_area_esc(tub_t *tubp, char **cpp) +{ + int lastx = GEOM_INPUT; + int c; + int i; + int start, next, fill; + int quant[NUMQUANT]; + + if ((c = tty3270_next_char(tubp)) != '[') { + return; + } + + /* + * Parse potentially empty string "nn;nn;nn..." + */ + i = -1; + c = ';'; + do { + if (c == ';') { + if (++i == NUMQUANT) + break; + quant[i] = 0; + } else if (c < '0' || c > '9') { + break; + } else { + quant[i] = quant[i] * 10 + c - '0'; + } + } while ((c = tty3270_next_char(tubp)) != -1); + if (c == -1) { + return; + } + if (i >= NUMQUANT) { + return; + } + switch(c) { + case -1: + return; + case 'm': /* Set Attribute */ + for (next = 0; next <= i; next++) { + int type = -1, value = 0; + + if (tubp->tty_escx + 3 > MAX_TTY_ESCA) + break; + switch(quant[next]) { + case 0: /* Reset */ + tubp->tty_esca[tubp->tty_escx++] = TO_SA; + tubp->tty_esca[tubp->tty_escx++] = TAT_RESET; + tubp->tty_esca[tubp->tty_escx++] = TAR_RESET; + break; + case 1: /* Bright */ + case 2: /* Dim */ + case 4: /* Underscore */ + case 5: /* Blink */ + case 7: /* Reverse */ + case 8: /* Hidden */ + break; /* For now ... */ + /* Foreground Colors */ + case 30: /* Black */ + type = TAT_COLOR; value = TAC_DEFAULT; + break; + case 31: /* Red */ + type = TAT_COLOR; value = TAC_RED; + break; + case 32: /* Green */ + type = TAT_COLOR; value = TAC_GREEN; + break; + case 33: /* Yellow */ + type = TAT_COLOR; value = TAC_YELLOW; + break; + case 34: /* Blue */ + type = TAT_COLOR; value = TAC_BLUE; + break; + case 35: /* Magenta */ + type = TAT_COLOR; value = TAC_PINK; + break; + case 36: /* Cyan */ + type = TAT_COLOR; value = TAC_TURQ; + break; + case 37: /* White */ + type = TAT_COLOR; value = TAC_WHITE; + break; + case 39: /* Black */ + type = TAT_COLOR; value = TAC_DEFAULT; + break; + /* Background Colors */ + case 40: /* Black */ + case 41: /* Red */ + case 42: /* Green */ + case 43: /* Yellow */ + case 44: /* Blue */ + case 45: /* Magenta */ + case 46: /* Cyan */ + case 47: /* White */ + break; /* For now ... */ + /* Oops */ + default: + break; + } + if (type != -1) { + tubp->tty_esca[tubp->tty_escx++] = TO_SA; + tubp->tty_esca[tubp->tty_escx++] = type; + tubp->tty_esca[tubp->tty_escx++] = value; + } + } + break; + case 'H': /* Cursor Home */ + case 'f': /* Force Cursor Position */ + return; + case 'A': /* Cursor Up */ + return; + case 'B': /* Cursor Down */ + return; + case 'C': /* Cursor Forward */ + next = tubp->tty_nextlogx % GEOM_COLS; + start = tubp->tty_nextlogx - next; + next = start + MIN(next + quant[i], GEOM_COLS - 1); + next = MIN(next, lastx); +do_fill: + fill = next - tubp->tty_nextlogx; + if (fill < 5) { + for (i = 0; i < fill; i++) + *(*cpp)++ = tub_ascebc[' ']; + } else { + *(*cpp)++ = TO_RA; + TUB_BUFADR(next, cpp); + *(*cpp)++ = tub_ascebc[' ']; + } + tubp->tty_nextlogx = next; + tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS; + break; + case 'D': /* Cursor Backward */ + next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS); + tubp->tty_nextlogx -= next; + tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS; + *(*cpp)++ = TO_SBA; + TUB_BUFADR(tubp->tty_nextlogx, cpp); + break; + case 'G': + start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS; + next = MIN(quant[i], GEOM_COLS - 1) + start; + next = MIN(next, lastx); + goto do_fill; + } +} + + +static int +tty3270_next_char(tub_t *tubp) +{ + int c; + bcb_t *ib; + + ib = &tubp->tty_bcb; + if (ib->bc_cnt == 0) + return -1; + c = ib->bc_buf[ib->bc_rd++]; + if (ib->bc_rd == ib->bc_len) + ib->bc_rd = 0; + ib->bc_cnt--; + return c; +} + + +static void +tty3270_clear_input_area(tub_t *tubp, char **cpp) +{ + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_INPUT, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = tubp->tty_inattr; + *(*cpp)++ = TO_IC; + *(*cpp)++ = TO_RA; + TUB_BUFADR(GEOM_STAT, cpp); + *(*cpp)++ = '\0'; +} + +static void +tty3270_update_input_area(tub_t *tubp, char **cpp) +{ + int len; + + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_INPUT, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = TF_INMDT; + len = strlen(tubp->tty_input); + memcpy(*cpp, tubp->tty_input, len); + *cpp += len; + *(*cpp)++ = TO_IC; + len = GEOM_INPLEN - len; + if (len > 4) { + *(*cpp)++ = TO_RA; + TUB_BUFADR(GEOM_STAT, cpp); + *(*cpp)++ = '\0'; + } else { + for (; len > 0; len--) + *(*cpp)++ = '\0'; + } +} + +/* + * tty3270_set_status_area(tub_t *tubp, char **cpp) + */ +static void +tty3270_set_status_area(tub_t *tubp, char **cpp) +{ + char *sp; + + if (tubp->stat == TBS_RUNNING) + sp = TS_RUNNING; + else if (tubp->stat == TBS_MORE) + sp = TS_MORE; + else if (tubp->stat == TBS_HOLD) + sp = TS_HOLD; + else + sp = "Linux Whatstat"; + + *(*cpp)++ = TO_SBA; + TUB_BUFADR(GEOM_STAT, cpp); + *(*cpp)++ = TO_SF; + *(*cpp)++ = TF_STAT; + memcpy(*cpp, sp, sizeof TS_RUNNING); + TUB_ASCEBC(*cpp, sizeof TS_RUNNING); + *cpp += sizeof TS_RUNNING; +} + +/* + * tty3270_build() -- build an output stream + */ +int +tty3270_build(tub_t *tubp) +{ + char *cp, *startcp; + int chancmd; + int writecc = TW_KR; + int force = 0; + + if (tubp->mode == TBM_FS) + return 0; + + cp = startcp = *tubp->ttyscreen + 1; + + switch(tubp->cmd) { + default: + printk(KERN_WARNING "tty3270_build unknown command %d\n", tubp->cmd); + return 0; + case TBC_OPEN: + chancmd = TC_EWRITEA; + tty3270_clear_input_area(tubp, &cp); + tty3270_set_status_area(tubp, &cp); + tty3270_clear_log_area(tubp, &cp); + break; + case TBC_UPDLOG: + chancmd = TC_WRITE; + writecc = TW_NONE; + tty3270_update_log_area(tubp, &cp); + break; + case TBC_KRUPDLOG: + chancmd = TC_WRITE; + force = 1; + tty3270_update_log_area(tubp, &cp); + break; + case TBC_CLRUPDLOG: + chancmd = TC_WRITE; + tty3270_set_status_area(tubp, &cp); + tty3270_clear_log_area(tubp, &cp); + tty3270_update_log_area(tubp, &cp); + break; + case TBC_UPDATE: + chancmd = TC_EWRITEA; + tubp->tty_oucol = tubp->tty_nextlogx = 0; + tty3270_clear_input_area(tubp, &cp); + tty3270_set_status_area(tubp, &cp); + tty3270_update_log_area(tubp, &cp); + break; + case TBC_UPDSTAT: + chancmd = TC_WRITE; + tty3270_set_status_area(tubp, &cp); + break; + case TBC_CLRINPUT: + chancmd = TC_WRITE; + tty3270_clear_input_area(tubp, &cp); + break; + case TBC_UPDINPUT: + chancmd = TC_WRITE; + tty3270_update_input_area(tubp, &cp); + break; + } + + /* Set Write Control Character and start I/O */ + if (force == 0 && cp == startcp && + (tubp->flags & TUB_ALARM) == 0) + return 0; + if (tubp->flags & TUB_ALARM) { + tubp->flags &= ~TUB_ALARM; + writecc |= TW_PLUSALARM; + } + **tubp->ttyscreen = writecc; + tubp->ttyccw.cmd_code = chancmd; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(*tubp->ttyscreen); + tubp->ttyccw.count = cp - *tubp->ttyscreen; + tty3270_io(tubp); + return 1; +} + +static void +tty3270_tub_bufadr(tub_t *tubp, int adr, char **cpp) +{ + if (tubp->tty_14bitadr) { + *(*cpp)++ = (adr >> 8) & 0x3f; + *(*cpp)++ = adr & 0xff; + } else { + *(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f]; + *(*cpp)++ = tub_ebcgraf[adr & 0x3f]; + } +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttyrcl.c linux/drivers/s390/char/tubttyrcl.c --- v2.4.3/linux/drivers/s390/char/tubttyrcl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubttyrcl.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,199 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttyrcl.c -- Linemode Command-recall functionality + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + +int +tty3270_rcl_init(tub_t *tubp) +{ + return tty3270_rcl_resize(tubp, 20); +} + +int +tty3270_rcl_resize(tub_t *tubp, int newrclk) +{ + char *(*newrclb)[]; + + if (newrclk > 1000) + return -EINVAL; + if (newrclk <= 0) { + tty3270_rcl_purge(tubp), + kfree(tubp->tty_rclbufs); + tubp->tty_rclbufs = NULL; + return 0; + } + if ((newrclb = (char *(*)[])kmalloc( + newrclk * sizeof (char *), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(newrclb, 0, newrclk * sizeof (char *)); + if (tubp->tty_rclbufs != NULL) { + int i, j, k; + char *data; + + i = tubp->tty_rclp; + j = newrclk; + k = tubp->tty_rclk; + while (j-- && k--) { + if ((data = (*tubp->tty_rclbufs)[i]) == NULL) + break; + (*newrclb)[j] = data; + (*tubp->tty_rclbufs)[i] = NULL; + if (--i < 0) + i = tubp->tty_rclk - 1; + } + tty3270_rcl_purge(tubp); + kfree(tubp->tty_rclbufs); + } + tubp->tty_rclbufs = newrclb; + tubp->tty_rclk = newrclk; + tubp->tty_rclp = newrclk - 1; + tty3270_rcl_sync(tubp); + return 0; +} + +int +tty3270_rcl_set(tub_t *tubp, char *buf, int count) +{ +#define RCL_SIZ "recallsize=" +#define L_RCL_SIZ (strlen(RCL_SIZ)) + int newsize; + int len; + int rc; + char *rcl_siz = RCL_SIZ; + int l_rcl_siz = L_RCL_SIZ; + + if (count < l_rcl_siz || strncmp(buf, rcl_siz, l_rcl_siz) != 0) + return 0; + if ((len = count - l_rcl_siz) == 0) + return count; + newsize = simple_strtoul(buf + l_rcl_siz, 0, 0); + rc = tty3270_rcl_resize(tubp, newsize); + return rc < 0? rc: count; +} + +void +tty3270_rcl_fini(tub_t *tubp) +{ + if (tubp->tty_rclbufs != NULL) { + tty3270_rcl_purge(tubp); + kfree(tubp->tty_rclbufs); + tubp->tty_rclbufs = NULL; + } +} + +void +tty3270_rcl_purge(tub_t *tubp) +{ + int i; + char *buf; + + if (tubp->tty_rclbufs == NULL) + return; + for (i = 0; i < tubp->tty_rclk; i++) { + if ((buf = (*tubp->tty_rclbufs)[i]) == NULL) + continue; + kfree(buf); + (*tubp->tty_rclbufs)[i] = NULL; + } +} + +int +tty3270_rcl_get(tub_t *tubp, char *buf, int len, int inc) +{ + int iter; + int i; + char *data; + + if (tubp->tty_rclbufs == NULL) + return 0; + if (tubp->tty_rclk <= 0) /* overcautious */ + return 0; + if (inc != 1 && inc != -1) /* overcautious */ + return 0; + + if ((i = tubp->tty_rclb) == -1) { + i = tubp->tty_rclp; + if (inc == 1) + i++; + } else { + i += inc; + } + for (iter = tubp->tty_rclk; iter; iter--, i += inc) { + if (i < 0) + i = tubp->tty_rclk - 1; + else if (i >= tubp->tty_rclk) + i = 0; + if ((*tubp->tty_rclbufs)[i] != NULL) + break; + } + if (iter < 0 || (data = (*tubp->tty_rclbufs)[i]) == NULL) + return 0; + tubp->tty_rclb = i; + if ((len = MIN(len - 1, strlen(data))) <= 0) + return 0; + memcpy(buf, data, len); + buf[len] = '\0'; + return len; +} + +void +tty3270_rcl_put(tub_t *tubp, char *data, int len) +{ + char *buf, **bufp; + int i; + + if (tubp->tty_rclbufs == NULL) + return; + + if (tubp->tty_rclk <= 0) /* overcautious */ + return; + + /* If input area is invisible, don't log */ + if (tubp->tty_inattr == TF_INPUTN) + return; + + /* If this & most recent cmd text match, don't log */ + if ((buf = (*tubp->tty_rclbufs)[tubp->tty_rclp]) != NULL && + strlen(buf) == len && memcmp(buf, data, len) == 0) { + tty3270_rcl_sync(tubp); + return; + } + + /* Don't stack zero-length commands */ + if (len == 0) { + tty3270_rcl_sync(tubp); + return; + } + + i = tubp->tty_rclp; + if (++i == tubp->tty_rclk) + i = 0; + bufp = &(*tubp->tty_rclbufs)[i]; + if (*bufp == NULL || strlen(*bufp) < len + 1) { + if (*bufp) { + kfree(*bufp); + *bufp = NULL; + } + if ((*bufp = kmalloc(len + 1, GFP_ATOMIC)) == NULL) + return; + } + memcpy(*bufp, data, len); + (*bufp)[len] = '\0'; + tubp->tty_rclp = i; + tty3270_rcl_sync(tubp); +} + +void +tty3270_rcl_sync(tub_t *tubp) +{ + tubp->tty_rclb = -1; +} + diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttyscl.c linux/drivers/s390/char/tubttyscl.c --- v2.4.3/linux/drivers/s390/char/tubttyscl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubttyscl.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,88 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC + * + * tubttyscl.c -- Linemode tty driver scroll-timing functions + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" + void tty3270_scl_settimer(tub_t *); + void tty3270_scl_resettimer(tub_t *); +static void tty3270_scl_timeout(unsigned long); + +void +tty3270_scl_settimer(tub_t *tubp) +{ + struct timer_list *tp = &tubp->tty_stimer; + + if (tubp->flags & TUB_SCROLLTIMING) + return; + if (tubp->tty_scrolltime == 0) + return; + + init_timer(tp); + tp->expires = jiffies + HZ * tubp->tty_scrolltime; + tp->data = (unsigned long)tubp; + tp->function = tty3270_scl_timeout; + add_timer(tp); + tubp->flags |= TUB_SCROLLTIMING; +} + +void +tty3270_scl_resettimer(tub_t *tubp) +{ + struct timer_list *tp = &tubp->tty_stimer; + + if ((tubp->flags & TUB_SCROLLTIMING) == 0) + return; + + del_timer(tp); + tubp->flags &= ~TUB_SCROLLTIMING; +} + +static void +tty3270_scl_timeout(unsigned long data) +{ + tub_t *tubp = (void *)data; + int flags; + + TUBLOCK(tubp->irq, flags); + tubp->stat = TBS_RUNNING; + tty3270_scl_resettimer(tubp); + tubp->cmd = TBC_CLRUPDLOG; + tty3270_build(tubp); + TUBUNLOCK(tubp->irq, flags); +} + +int +tty3270_scl_set(tub_t *tubp, char *buf, int count) +{ + if (strncmp(buf, "scrolltime=", 11) == 0) { + tubp->tty_scrolltime = + simple_strtoul(buf + 11, 0, 0); + return count; + } + return 0; +} + +int +tty3270_scl_init(tub_t *tubp) +{ + extern int tubscrollparm; + + tubp->tty_scrolltime = tubscrollparm; + if (tubp->tty_scrolltime < 0) + tubp->tty_scrolltime = DEFAULT_SCROLLTIME; + return 0; +} + +void +tty3270_scl_fini(tub_t *tubp) +{ + if ((tubp->flags & TUB_OPEN_STET) == 0) + tty3270_scl_resettimer(tubp); +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/tubttysiz.c linux/drivers/s390/char/tubttysiz.c --- v2.4.3/linux/drivers/s390/char/tubttysiz.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/char/tubttysiz.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,304 @@ +/* + * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC + * + * tubttysiz.c -- Linemode screen-size determiner + * + * + * + * + * + * Author: Richard Hitt + */ +#include "tubio.h" +static int tty3270_size_io(tub_t *tubp); +static void tty3270_size_int(tub_t *tubp, devstat_t *dsp); +static int tty3270_size_wait(tub_t *tubp, int *flags, int stat); + +/* + * Structure representing Usable Area Query Reply Base + */ +typedef struct { + short l; /* Length of this structured field */ + char sfid; /* 0x81 if Query Reply */ + char qcode; /* 0x81 if Usable Area */ +#define QCODE_UA 0x81 + char flags0; +#define FLAGS0_ADDR 0x0f +#define FLAGS0_ADDR_12_14 1 /* 12/14-bit adrs ok */ +#define FLAGS0_ADDR_12_14_16 3 /* 12/14/16-bit adrs ok */ + char flags1; + short w; /* Width of usable area */ + short h; /* Heigth of usavle area */ + char units; /* 0x00:in; 0x01:mm */ + int xr; + int yr; + char aw; + char ah; + short buffsz; /* Character buffer size, bytes */ + char xmin; + char ymin; + char xmax; + char ymax; +} __attribute__ ((packed)) uab_t; + +/* + * Structure representing Alternate Usable Area Self-Defining Parameter + */ +typedef struct { + char l; /* Length of this Self-Defining Parm */ + char sdpid; /* 0x02 if Alternate Usable Area */ +#define SDPID_AUA 0x02 + char res; + char auaid; /* 0x01 is Id for the A U A */ + short wauai; /* Width of AUAi */ + short hauai; /* Height of AUAi */ + char auaunits; /* 0x00:in, 0x01:mm */ + int auaxr; + int auayr; + char awauai; + char ahauai; +} __attribute__ ((packed)) aua_t; + +/* + * Structure representing one followed by the other + */ +typedef struct { + uab_t uab; + aua_t aua; +} __attribute__ ((packed)) ua_t; + +/* + * Try to determine screen size using Read Partition (Query) + */ +int +tty3270_size(tub_t *tubp, int *flags) +{ + char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; + int rc = 0; + int count; + unsigned char *cp; + ua_t *uap; + char miniscreen[256]; + char (*screen)[]; + int screenl; + int geom_rows, geom_cols, fourteenbitadr; + void (*oldint)(struct tub_s *, devstat_t *); + + if (tubp->flags & TUB_SIZED) + return 0; + fourteenbitadr = 0; + geom_rows = tubp->geom_rows; + geom_cols = tubp->geom_cols; + + oldint = tubp->intv; + tubp->intv = tty3270_size_int; + + if (tubp->cmd == TBC_CONOPEN) { + tubp->ttyccw.cmd_code = TC_EWRITEA; + cp = miniscreen; + *cp++ = TW_KR; + /* more? */ + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(miniscreen); + tubp->ttyccw.count = (char *)cp - miniscreen; + rc = tty3270_size_io(tubp); + rc = tty3270_size_wait(tubp, flags, 0); + } + + tubp->ttyccw.cmd_code = TC_WRITESF; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(wbuf); + tubp->ttyccw.count = sizeof wbuf; + +try_again: + rc = tty3270_size_io(tubp); + if (rc) + printk("tty3270_size_io returned %d\n", rc); + + rc = tty3270_size_wait(tubp, flags, 0); + if (rc != 0) { + goto do_return; + } + + /* + * Unit-Check Processing: + * Expect Command Reject or Intervention Required. + * For Command Reject assume old hdwe/software and + * set a default size of 80x24. + * For Intervention Required, wait for signal pending + * or Unsolicited Device End; if the latter, retry. + */ + if (tubp->dstat & DEV_STAT_UNIT_CHECK) { + if (tubp->sense.data[0] & SNS0_CMD_REJECT) { + goto use_diag210; /* perhaps it's tn3270 */ + } else if (tubp->sense.data[0] & SNS0_INTERVENTION_REQ) { + if ((rc = tty3270_size_wait(tubp, flags, + DEV_STAT_DEV_END))) + goto do_return; + goto try_again; + } else { + printk("tty3270_size(): unkn sense %.2x\n", + tubp->sense.data[0]); + goto do_return; + } + } + if ((rc = tty3270_size_wait(tubp, flags, DEV_STAT_ATTENTION))) + goto do_return; + + /* Set up a read ccw and issue it */ + tubp->ttyccw.cmd_code = TC_READMOD; + tubp->ttyccw.flags = CCW_FLAG_SLI; + tubp->ttyccw.cda = virt_to_phys(miniscreen); + tubp->ttyccw.count = sizeof miniscreen; + tty3270_size_io(tubp); + rc = tty3270_size_wait(tubp, flags, 0); + if (rc != 0) + goto do_return; + + count = sizeof miniscreen - tubp->cswl; + cp = miniscreen; + if (*cp++ != 0x88) + goto do_return; + uap = (void *)cp; + if (uap->uab.qcode != QCODE_UA) + goto do_return; + geom_rows = uap->uab.h; + geom_cols = uap->uab.w; + if ((uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14 || + (uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14_16) + fourteenbitadr = 1; + if (uap->uab.l <= sizeof uap->uab) + goto do_return; + if (uap->aua.sdpid != SDPID_AUA) { + printk("AUA sdpid was 0x%.2x, expecting 0x%.2x\n", + uap->aua.sdpid, SDPID_AUA); + goto do_return; + } + geom_rows = uap->aua.hauai; + geom_cols = uap->aua.wauai; + goto do_return; + +use_diag210: + if (MACHINE_IS_VM) { + diag210_t d210; + + d210.vrdcdvno = tubp->devno; + d210.vrdclen = sizeof d210; + rc = diag210(&d210); + if (rc) { + printk("tty3270_size: diag210 for 0x%.4x " + "returned %d\n", tubp->devno, rc); + goto do_return; + } + switch(d210.vrdccrmd) { + case 2: + geom_rows = 24; + geom_cols = 80; + goto do_return; + case 3: + geom_rows = 32; + geom_cols = 80; + goto do_return; + case 4: + geom_rows = 43; + geom_cols = 80; + goto do_return; + case 5: + geom_rows = 27; + geom_cols = 132; + goto do_return; + default: + printk("vrdccrmd is 0x%.8x\n", d210.vrdccrmd); + } + } + +do_return: + if (geom_rows == 0) { + geom_rows = _GEOM_ROWS; + geom_cols = _GEOM_COLS; + } + tubp->tubiocb.pf_cnt = 24; + tubp->tubiocb.re_cnt = 20; + tubp->tubiocb.map = 0; + + screenl = geom_rows * geom_cols + 100; + screen = (char (*)[])kmalloc(screenl, GFP_KERNEL); + if (screen == NULL) { + printk("ttyscreen size %d unavailable\n", screenl); + } else { + if (tubp->ttyscreen) + kfree(tubp->ttyscreen); + tubp->tubiocb.line_cnt = tubp->geom_rows = geom_rows; + tubp->tubiocb.col_cnt = tubp->geom_cols = geom_cols; + tubp->tty_14bitadr = fourteenbitadr; + tubp->ttyscreen = screen; + tubp->ttyscreenl = screenl; + if (geom_rows == 24 && geom_cols == 80) + tubp->tubiocb.model = 2; + else if (geom_rows == 32 && geom_cols == 80) + tubp->tubiocb.model = 3; + else if (geom_rows == 43 && geom_cols == 80) + tubp->tubiocb.model = 4; + else if (geom_rows == 27 && geom_cols == 132) + tubp->tubiocb.model = 5; + else + tubp->tubiocb.model = 0; + tubp->flags |= TUB_SIZED; + } + if (rc == 0 && tubp->ttyscreen == NULL) + rc = -ENOMEM; + tubp->intv = oldint; + return rc; +} + +static int +tty3270_size_io(tub_t *tubp) +{ + tubp->flags |= TUB_WORKING; + tubp->dstat = 0; + + return do_IO(tubp->irq, &tubp->ttyccw, tubp->irq, 0, 0); +} + +static void +tty3270_size_int(tub_t *tubp, devstat_t *dsp) +{ +#define DEV_NOT_WORKING \ + (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK) + + tubp->dstat = dsp->dstat; + if (dsp->dstat & DEV_STAT_CHN_END) + tubp->cswl = dsp->rescnt; + if (dsp->dstat & DEV_NOT_WORKING) + tubp->flags &= ~TUB_WORKING; + if (dsp->dstat & DEV_STAT_UNIT_CHECK) + tubp->sense = dsp->ii.sense; + + wake_up_interruptible(&tubp->waitq); +} + +/* + * Wait for something. If the third arg is zero, wait until + * tty3270_size_int() turns off TUB_WORKING. If the third arg + * is not zero, it is a device-status bit; wait until dstat + * has the bit turned on. Never wait if signal is pending. + * Return 0 unless signal pending, in which case -ERESTARTSYS. + */ +static int +tty3270_size_wait(tub_t *tubp, int *flags, int stat) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&tubp->waitq, &wait); + while (!signal_pending(current) && + (stat? (tubp->dstat & stat) == 0: + (tubp->flags & TUB_WORKING) != 0)) { + current->state = TASK_INTERRUPTIBLE; + TUBUNLOCK(tubp->irq, *flags); + schedule(); + current->state = TASK_RUNNING; + TUBLOCK(tubp->irq, *flags); + } + remove_wait_queue(&tubp->waitq, &wait); + return signal_pending(current)? -ERESTARTSYS: 0; +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/idals.c linux/drivers/s390/idals.c --- v2.4.3/linux/drivers/s390/idals.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/idals.c Wed Apr 11 19:02:28 2001 @@ -9,6 +9,7 @@ * 12/13/00 changed IDALs to 4kByte-IDALs */ +#include <linux/module.h> #include <linux/config.h> #include <linux/malloc.h> @@ -16,6 +17,8 @@ #include <asm/idals.h> #ifdef CONFIG_ARCH_S390X +#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */ +#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG) void set_normalized_cda ( ccw1_t * cp, unsigned long address ) { @@ -25,11 +28,12 @@ if (cp->flags & CCW_FLAG_IDA) BUG(); - if (((address + count) >> 31) == 0) { /* do we really need '+count'? */ + if (((address + count) >> 31) == 0) { cp -> cda = address; return; } - nridaws = ((address & 4095L) + count + 4095L) >> 12; + nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + + (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; idal = idal_alloc(nridaws); if ( idal == NULL ) { /* probably we should have a fallback here */ @@ -39,9 +43,12 @@ cp->cda = (__u32)(unsigned long)(idaw_t *)idal; do { *idal++ = address; - address = (address & -4096L) + 4096; + address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE); nridaws --; } while ( nridaws > 0 ); return; } + +EXPORT_SYMBOL (set_normalized_cda); + #endif diff -u --recursive --new-file v2.4.3/linux/drivers/s390/misc/Makefile linux/drivers/s390/misc/Makefile --- v2.4.3/linux/drivers/s390/misc/Makefile Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/misc/Makefile Wed Apr 11 19:02:28 2001 @@ -1,9 +1,10 @@ -all: s390-misc.o +# +# S/390 miscellaneous devices +# -CFLAFS += O_TARGET := s390-misc.o obj-$(CONFIG_CHANDEV) += chandev.o +export-objs += chandev.o include $(TOPDIR)/Rules.make - diff -u --recursive --new-file v2.4.3/linux/drivers/s390/misc/chandev.c linux/drivers/s390/misc/chandev.c --- v2.4.3/linux/drivers/s390/misc/chandev.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/misc/chandev.c Wed Apr 11 19:02:28 2001 @@ -6,7 +6,10 @@ * * Generic channel device initialisation support. */ +#define TRUE 1 +#define FALSE 0 #define __KERNEL_SYSCALLS__ +#include <linux/module.h> #include <linux/config.h> #include <linux/types.h> #include <linux/ctype.h> @@ -20,6 +23,7 @@ #include <linux/vmalloc.h> #include <asm/s390dyn.h> #include <asm/queue.h> +#include <linux/kmod.h> typedef struct chandev_model_info chandev_model_info; struct chandev_model_info @@ -229,6 +233,7 @@ static long chandev_lock_owner; static int chandev_lock_cnt; static spinlock_t chandev_spinlock; +void *chandev_firstlock_addr,*chandev_lastlock_addr; typedef struct chandev_not_oper_struct chandev_not_oper_struct; @@ -256,24 +261,6 @@ for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next) -#define CHANDEV_USE_KERNEL_THREADS (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0)) - -#if CHANDEV_USE_KERNEL_THREADS -static void chandev_start_msck_thread(void *unused); -#if LINUX_VERSION_CODE<KERNEL_VERSION(2,3,0) -#define chandev_daemonize(name,mask,use_init_fs) s390_daemonize(name,mask) -#else -#define chandev_daemonize(args...) s390_daemonize(args) -#endif -typedef int chandev_task_retval; -#define chandev_task_return(val) return(val) -#else -#define chandev_daemonize(noargs...) -#define chandev_task_retval void -#define chandev_task_return(val) return -#endif - - static void chandev_lock(void) { chandev_interrupt_check(); @@ -283,18 +270,33 @@ spin_lock(&chandev_spinlock); chandev_lock_cnt=1; chandev_lock_owner=(long)current; + chandev_firstlock_addr=__builtin_return_address(0); } else + { chandev_lock_cnt++; + chandev_lastlock_addr=__builtin_return_address(0); + } if(chandev_lock_cnt<0||chandev_lock_cnt>100) - panic("odd lock_cnt in lcs %d lcs_chan_lock",chandev_lock_cnt); + { + printk("odd lock_cnt %d lcs_chan_lock",chandev_lock_cnt); + chandev_lock_cnt=1; + } } +static int chandev_full_unlock(void) +{ + int ret_lock_cnt=chandev_lock_cnt; + chandev_lock_cnt=0; + chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER; + spin_unlock(&chandev_spinlock); + return(ret_lock_cnt); +} static void chandev_unlock(void) { if(chandev_lock_owner!=(long)current) - panic("chandev_unlock: current=%lx" + printk("chandev_unlock: current=%lx" " chandev_lock_owner=%lx chandev_lock_cnt=%d\n", (long)current, chandev_lock_owner, @@ -305,19 +307,20 @@ spin_unlock(&chandev_spinlock); } if(chandev_lock_cnt<0) - panic("odd lock_cnt in lcs %d lcs_chan_unlock",chandev_lock_cnt); -} + { + printk("odd lock_cnt=%d in chan_unlock",chandev_lock_cnt); + chandev_full_unlock(); + } -int chandev_full_unlock(void) -{ - int ret_lock_cnt=chandev_lock_cnt; - chandev_lock_cnt=0; - chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER; - spin_unlock(&chandev_spinlock); - return(ret_lock_cnt); } +void chandev_relock(int saved_lock_cnt) +{ + + chandev_lock(); + chandev_lock_cnt=saved_lock_cnt; +} void *chandev_alloc(size_t size) @@ -405,145 +408,8 @@ } -struct files_struct *chandev_new_files_struct(void) -{ - struct files_struct *newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); - if (!newf) - return(NULL); - memset(newf,0,sizeof(struct files_struct)); - atomic_set(&newf->count, 1); - newf->file_lock = RW_LOCK_UNLOCKED; - newf->next_fd = 0; - newf->max_fds = NR_OPEN_DEFAULT; - newf->max_fdset = __FD_SETSIZE; - newf->close_on_exec = &newf->close_on_exec_init; - newf->open_fds = &newf->open_fds_init; - newf->fd = &newf->fd_array[0]; - return(newf); -} -/* - * Mostly robbed from kmod.c - */ -static inline void -use_init_fs_context(void) -{ - struct fs_struct *our_fs, *init_fs; - struct dentry *root, *pwd; - struct vfsmount *rootmnt, *pwdmnt; - - /* - * Make modprobe's fs context be a copy of init's. - * - * We cannot use the user's fs context, because it - * may have a different root than init. - * Since init was created with CLONE_FS, we can grab - * its fs context from "init_task". - * - * The fs context has to be a copy. If it is shared - * with init, then any chdir() call in modprobe will - * also affect init and the other threads sharing - * init_task's fs context. - * - * We created the exec_modprobe thread without CLONE_FS, - * so we can update the fields in our fs context freely. - */ - - init_fs = init_task.fs; - read_lock(&init_fs->lock); - rootmnt = mntget(init_fs->rootmnt); - root = dget(init_fs->root); - pwdmnt = mntget(init_fs->pwdmnt); - pwd = dget(init_fs->pwd); - read_unlock(&init_fs->lock); - - /* FIXME - unsafe ->fs access */ - our_fs = current->fs; - our_fs->umask = init_fs->umask; - set_fs_root(our_fs, rootmnt, root); - set_fs_pwd(our_fs, pwdmnt, pwd); - write_lock(&our_fs->lock); - if (our_fs->altroot) { - struct vfsmount *mnt = our_fs->altrootmnt; - struct dentry *dentry = our_fs->altroot; - our_fs->altrootmnt = NULL; - our_fs->altroot = NULL; - write_unlock(&our_fs->lock); - dput(dentry); - mntput(mnt); - } else - write_unlock(&our_fs->lock); - dput(root); - mntput(rootmnt); - dput(pwd); - mntput(pwdmnt); -} - - -static int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) -{ - int err; - wait_queue_head_t wait; - - - current->session = 1; - current->pgrp = 1; - - /* We copy this off init & can't go until this is set up */ - init_waitqueue_head(&wait); - while(init_task.fs->root==NULL) - { - sleep_on_timeout(&wait,HZ); - } - use_init_fs_context(); - - /* Prevent parent user process from sending signals to child. - Otherwise, if the modprobe program does not exist, it might - be possible to get a user defined signal handler to execute - as the super user right after the execve fails if you time - the signal just right. - */ - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - flush_signal_handlers(current); - spin_unlock_irq(¤t->sigmask_lock); - /* current->files sometimes was null this means we need */ - /* to build our own */ - exit_files(current); - if((current->files=chandev_new_files_struct())==NULL) - { - printk("chandev_new_files_struct allocation failed\n"); - return(0); - } - - /* Drop the "current user" thing */ - { - struct user_struct *user = current->user; - current->user = INIT_USER; - atomic_inc(&INIT_USER->__count); - atomic_inc(&INIT_USER->processes); - atomic_dec(&user->processes); - free_uid(user); - } - - /* Take all effective privileges.. */ - current->uid = current->euid = current->fsuid = 0; - cap_set_full(current->cap_effective); - /* Allow execve & open args to be in kernel space. */ - set_fs(KERNEL_DS); - /* We need stdin out & err for scripts */ - if (open("/dev/console", O_RDWR, 0)< 0) - printk("chandev exec_usermode_helper unable to open an initial console.\n"); - (void) dup(0); - (void) dup(0); - - - /* Go, go, go... */ - err=execve(program_path, argv, envp); - return err; -} - -static int exec_start_script(void *unused) +static int chandev_exec_start_script(void *unused) { char **argv,*tempname; @@ -555,7 +421,8 @@ static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; init_waitqueue_head(&wait); - s390_daemonize("chandev_script",0,FALSE); + strcpy(current->comm,"chandev_script"); + for(loopcnt=0;loopcnt<10&&(jiffies-chandev_last_startmsck_list_update)<HZ;loopcnt++) { sleep_on_timeout(&wait,HZ); @@ -612,6 +479,12 @@ chandev_free_all_list((list **)&startlist_head); chandev_free_all_list((list **)&mscklist_head); chandev_unlock(); + + /* We need to wait till there is a root filesystem */ + while(init_task.fs->root==NULL) + { + sleep_on_timeout(&wait,HZ); + } /* We are basically execve'ing here there normally is no */ /* return */ retval=exec_usermodehelper(exec_script, argv, envp); @@ -623,7 +496,7 @@ Fail2: /* We don't really need to report /bin/chandev not existing */ if(retval!=-ENOENT) - printk("exec_start_script failed retval=%d\n",retval); + printk("chandev_exec_start_script failed retval=%d\n",retval); return(0); } @@ -643,7 +516,6 @@ static int chandev_add_to_startmsck_list(chandev_startmsck_list **listhead,char *devname, chandev_msck_status pre_recovery_action_status,chandev_msck_status post_recovery_action_status) { - int retval; chandev_startmsck_list *member; int pid; @@ -664,14 +536,11 @@ add_to_list((list **)listhead,(list *)member); chandev_last_startmsck_list_update=jiffies; chandev_unlock(); - /* We do CLONE_FILES so we can exit_files to get rid of it */ - /* cheaply & allocate a new one we need current->files & */ - /* some tasks have current->files==NULL */ - pid = kernel_thread(exec_start_script,NULL,CLONE_FILES|SIGCHLD); + pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD); if(pid<0) { - printk("error making kernel thread for exec_start_script\n"); - retval=pid; + printk("error making kernel thread for chandev_exec_start_script\n"); + return(pid); } else return(0); @@ -679,11 +548,10 @@ } else { + chandev_unlock(); printk("chandev_add_to_startmscklist memory allocation failed devname=%s\n",devname); - retval=-ENOMEM; + return(-ENOMEM); } - chandev_unlock(); - return(retval); } @@ -695,11 +563,7 @@ chandev_last_machine_check=jiffies; if(atomic_dec_and_test(&chandev_msck_thread_lock)) { -#if CHANDEV_USE_KERNEL_THREADS - queue_task(&chandev_msck_task_tq,&tq_scheduler); -#else schedule_task(&chandev_msck_task_tq); -#endif } atomic_set(&chandev_new_msck,TRUE); return(0); @@ -719,11 +583,7 @@ spin_unlock(&chandev_not_oper_spinlock); if(atomic_dec_and_test(&chandev_msck_thread_lock)) { -#if CHANDEV_USE_KERNEL_THREADS - queue_task(&chandev_msck_task_tq,&tq_scheduler); -#else schedule_task(&chandev_msck_task_tq); -#endif } } else @@ -767,6 +627,18 @@ } +void chandev_remove_irqinfo_by_irq(unsigned int irq) +{ + chandev_irqinfo *remove_irqinfo; + + chandev_lock(); + /* remove any orphan irqinfo left lying around. */ + if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq))) + chandev_remove_from_list((list **)&chandev_irqinfo_head, + (list *)remove_irqinfo); + chandev_unlock(); + +} int chandev_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), @@ -790,9 +662,7 @@ return(-EPERM); } /* remove any orphan irqinfo left lying around. */ - if((new_irqinfo=chandev_get_irqinfo_by_irq(irq))) - chandev_remove_from_list((list **)chandev_irqinfo_head, - (list *)new_irqinfo); + chandev_remove_irqinfo_by_irq(irq); chandev_unlock(); if((new_irqinfo=chandev_allocstr(devname,offsetof(chandev_irqinfo,devname)))) { @@ -819,6 +689,12 @@ return(retval); } +void chandev_free_irq(unsigned int irq, void *dev_id) +{ + /* remove any orphan irqinfo left lying around. */ + chandev_remove_irqinfo_by_irq(irq); + free_irq(irq,dev_id); +} void chandev_sprint_type_model(char *buff,s32 type,s16 model) @@ -1148,6 +1024,7 @@ void chandev_shutdown(chandev_activelist *curr_device) { + int saved_lock_cnt; chandev_lock(); if(curr_device->category==network_device) @@ -1155,12 +1032,16 @@ /* unregister_netdev calls the dev->close so we shouldn't do this */ /* this otherwise we crash */ if(curr_device->unreg_dev) - curr_device->unreg_dev(curr_device->dev_ptr); + { + saved_lock_cnt=chandev_full_unlock(); + curr_device->unreg_dev(curr_device->dev_ptr); + chandev_relock(saved_lock_cnt); + } } + saved_lock_cnt=chandev_full_unlock(); curr_device->shutdownfunc(curr_device->dev_ptr); + chandev_relock(saved_lock_cnt); kfree(curr_device->dev_ptr); - chandev_free_listmember((list **)&chandev_irqinfo_head,(list *)curr_device->read_irqinfo); - chandev_free_listmember((list **)&chandev_irqinfo_head,(list *)curr_device->write_irqinfo); chandev_free_listmember((list **)&chandev_activelist_head, (list *)curr_device); chandev_unlock(); @@ -1492,8 +1373,7 @@ /* as probefunctions can call schedule & */ /* reenter to do a kernel thread & we may deadlock */ rc=probefunc(&probeinfo); - chandev_lock(); - chandev_lock_cnt=saved_lock_cnt; + chandev_relock(saved_lock_cnt); if(rc==0) { newdevice=probeinfo.newdevice; @@ -1619,9 +1499,13 @@ if(curr_irqinfo->msck_status==good&&prevstatus!=good) { if(curr_device->reoperfunc) + { + int saved_lock_cnt=chandev_full_unlock(); curr_device->reoperfunc(curr_device->dev_ptr, (curr_device->read_irqinfo==curr_irqinfo), prevstatus); + chandev_relock(saved_lock_cnt); + } if(curr_device->category==network_device&& curr_device->write_irqinfo==curr_irqinfo) { @@ -1743,13 +1627,12 @@ } -static chandev_task_retval chandev_msck_task(void *unused) +static void chandev_msck_task(void *unused) { int loopcnt,not_oper_probe_required=FALSE; wait_queue_head_t wait; chandev_not_oper_struct *new_not_oper; - chandev_daemonize("chandev_msck_kernel_thread",0,TRUE); /* This loop exists because machine checks tend to come in groups & we have to wait for the other devnos to appear also */ init_waitqueue_head(&wait); @@ -1780,21 +1663,10 @@ } if(not_oper_probe_required) chandev_probe(); - chandev_task_return(0); } -#if CHANDEV_USE_KERNEL_THREADS -static void chandev_start_msck_thread(void *unused) -{ - /* tq_scheduler sometimes leaves interrupts disabled from do bottom half */ - __sti(); - kernel_thread((int (*)(void *))chandev_msck_task, - (void*)NULL,0); -} -#endif - static char *argstrs[]= @@ -1953,6 +1825,7 @@ chandev_type chan_type; char *str,*currstr,*interpretstr=NULL; int cnt,strcnt; + int retval=0; #define CHANDEV_MAX_EXTRA_INTS 8 chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1]; memset(ints,0,sizeof(ints)); @@ -2182,17 +2055,29 @@ else goto BadArgs; } - return(1); + retval=1; BadArgs: - printk("chandev_setup bad argument %s",instr); - if(errstr) + if(!retval) { - printk("%s %d interpreted as %s",errstr,lineno,interpretstr); - if(strcnt>1) - printk(" before semicolon no %d",cnt); + printk("chandev_setup bad argument %s",instr); + if(errstr) + { + printk("%s %d interpreted as %s",errstr,lineno,interpretstr); + if(strcnt>1) + printk(" before semicolon no %d",cnt); + } + printk(".\n Type man chandev for more info.\n\n"); } - printk(".\n Type man chandev for more info.\n\n"); - return(0); + eieio(); + if(chandev_lock_owner==(long)current) + { + printk("chandev_setup bug chandev_lock_cnt=%d lock_owner=%lx\n" + "firstlock_retaddr=%p last_lock_returnaddr=%p\n", + chandev_lock_cnt,chandev_lock_owner,chandev_firstlock_addr, + chandev_lastlock_addr); + chandev_full_unlock(); + } + return(retval); } #define CHANDEV_KEYWORD "chandev=" static int chandev_setup_bootargs(char *str,int paramno) @@ -2608,11 +2493,7 @@ chandev_create_proc(); #endif chandev_msck_task_tq.routine= -#if CHANDEV_USE_KERNEL_THREADS - chandev_start_msck_thread; -#else chandev_msck_task; -#endif #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0) INIT_LIST_HEAD(&chandev_msck_task_tq.list); chandev_msck_task_tq.sync=0; @@ -2684,4 +2565,13 @@ } chandev_unlock(); } + +EXPORT_SYMBOL(chandev_register_and_probe); +EXPORT_SYMBOL(chandev_request_irq); +EXPORT_SYMBOL(chandev_free_irq); +EXPORT_SYMBOL(chandev_unregister); +EXPORT_SYMBOL(chandev_initdevice); +EXPORT_SYMBOL(chandev_initnetdevice); + + diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile --- v2.4.3/linux/drivers/s390/net/Makefile Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/net/Makefile Wed Apr 11 19:02:28 2001 @@ -1,20 +1,20 @@ -all: s390-net.o +# +# S/390 network devices +# -CFLAGS += O_TARGET := s390-net.o -obj-y := iucv.o +list-multi := ctc.o +export-objs := iucv.o -ifeq ($(CONFIG_CTC),y) - obj-y += ctcmain.o fsm.o -else - ifeq ($(CONFIG_CTC),m) - obj-m += ctc.o -ctc.o: ctcmain.o fsm.o - $(LD) -r ctcmain.o fsm.o -o $@ - endif -endif +ctc-objs := ctcmain.o ctctty.o fsm.o -obj-$(CONFIG_IUCV) += iucv.o netiucv.o +obj-y += iucv.o +obj-$(CONFIG_CTC) += ctc.o +obj-$(CONFIG_IUCV) += netiucv.o include $(TOPDIR)/Rules.make + +ctc.o: $(ctc-objs) + $(LD) -r -o $@ $(ctc-objs) + diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c --- v2.4.3/linux/drivers/s390/net/ctc.c Fri Mar 2 11:12:07 2001 +++ linux/drivers/s390/net/ctc.c Wed Dec 31 16:00:00 1969 @@ -1,1582 +0,0 @@ -/* - * drivers/s390/net/ctc.c - * CTC / ESCON network driver - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Dieter Wellerdiek (wel@de.ibm.com) - * - * 2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com) - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * - * - * Description of the Kernel Parameter - * Normally the CTC driver selects the channels in order (automatic channel - * selection). If your installation needs to use the channels in a different - * order or doesn't want to have automatic channel selection on, you can do - * this with the "ctc= kernel keyword". - * - * ctc=0,0xrrrr,0xwwww,ddddd - * - * Where: - * - * "rrrr" is the read channel address - * "wwww" is the write channel address - * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 - * to escon7 for ESCON channels). - * - * To switch the automatic channel selection off use the ctc= keyword with - * parameter "noauto". This may be necessary if you 3271 devices or other devices - * which use the ctc device type and model, but operate with a different protocol. - * - * ctc=noauto - * - * Change History - * 0.50 Initial release shipped - * 0.51 Bug fixes - * - CTC / ESCON network device can now handle up to 64 channels - * - 3088-61 info message supperssed - CISCO 7206 - CLAW - ESCON - * - 3088-62 info message suppressed - OSA/D - * - channel: def ffffffed ... error message suppressed - * - CTC / ESCON device was not recoverable after a lost connection with - * IFCONFIG dev DOWN and IFCONFIG dev UP - * - Possibility to switch the automatic selection off - * - Minor bug fixes - */ -#include <linux/version.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/sched.h> - -#include <linux/signal.h> -#include <linux/string.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ip.h> -#include <linux/if_arp.h> -#include <linux/tcp.h> -#include <linux/skbuff.h> - -#include <asm/io.h> -#include <asm/bitops.h> - -#include <asm/irq.h> - - -//#define DEBUG - -/* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */ -#ifdef DEBUG - #undef KERN_INFO - #undef KERN_WARNING - #undef KERN_DEBUG - #define KERN_INFO KERN_EMERG - #define KERN_WARNING KERN_EMERG - #define KERN_DEBUG KERN_EMERG -#endif -//#undef DEBUG - -#define CCW_CMD_WRITE 0x01 -#define CCW_CMD_READ 0x02 -#define CCW_CMD_SET_EXTENDED 0xc3 -#define CCW_CMD_PREPARE 0xe3 - -#define MAX_CHANNEL_DEVICES 64 -#define MAX_ADAPTERS 8 -#define CTC_DEFAULT_MTU_SIZE 1500 -#define READ 0 -#define WRITE 1 -#define CTC 0 -#define ESCON 1 -#define CHANNEL_MEDIA 2 -#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */ - -#define TB_TX 0 /* sk buffer handling in process */ -#define TB_STOP 1 /* network device stop in process */ -#define TB_RETRY 2 /* retry in process */ -#define TB_NOBUFFER 3 /* no buffer on free queue */ - -/* state machine codes used in ctc_irq_handler */ -#define CTC_STOP 0 -#define CTC_START_HALT_IO 1 -#define CTC_START_SET_X_MODE 2 -#define CTC_START_SELECT 4 -#define CTC_START_READ_TEST 32 -#define CTC_START_READ 33 -#define CTC_START_WRITE_TEST 64 -#define CTC_START_WRITE 65 - - -typedef enum { - channel_type_none, /* Device is not a channel */ - channel_type_undefined, /* Device is a channel but we don't know anything about it */ - channel_type_ctca, /* Device is a CTC/A and we can deal with it */ - channel_type_escon, /* Device is a ESCON channel and we can deal with it */ - channel_type_unsupported /* Device is a unsupported model */ -} channel_type_t; - - - -/* - * Structures needed in the initial phase - * - */ - -/* long req'd by set_bit --RR */ -static long channel_tab_initialized = 0; /* channel[] structure initialized */ - -struct devicelist { - unsigned int devno; - __u8 flag; -#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */ -}; - -static struct { - struct devicelist list[MAX_CHANNEL_DEVICES]; - int count; - int left; -} channel[CHANNEL_MEDIA]; - - - -static int ctc_no_auto = 0; - -struct adapterlist{ - unsigned int devno[2]; - __u16 protocol; -}; - -static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */ - - -/* - * Structure used after the initial phase - * - */ - -struct buffer { - struct buffer *next; - int packets; - struct block *block; -}; - -#if LINUX_VERSION_CODE>=0x020300 -typedef struct net_device net_device; -#else -typedef struct device net_device; -typedef struct wait_queue* wait_queue_head_t; -#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue waitqname = {waitqtask, NULL } -#define init_waitqueue_head(nothing) -#endif - - -struct channel { - unsigned int devno; - int irq; - unsigned long IO_active; - ccw1_t ccw[3]; - __u32 state; - int buffer_count; - struct buffer *free_anchor; - struct buffer *proc_anchor; - devstat_t *devstat; - net_device *dev; /* backward pointer to the network device */ - wait_queue_head_t wait; - struct tq_struct tq; - struct timer_list timer; - unsigned long flag_a; /* atomic flags */ -#define CTC_BH_ACTIVE 0 - __u8 last_dstat; - __u8 flag; -#define CTC_WRITE 0x01 /* - Set if this is a write channel */ -#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ -}; - - -struct ctc_priv { - struct net_device_stats stats; -#if LINUX_VERSION_CODE>=0x02032D - int tbusy; -#endif - struct channel channel[2]; - __u16 protocol; -}; - -/* - * This structure works as shuttle between two systems - * - A block can contain one or more packets - */ - -#define PACKET_HEADER_LENGTH 6 -struct packet { - __u16 length; - __u16 type; - __u16 unused; - __u8 data; -}; - -#define BLOCK_HEADER_LENGTH 2 -struct block { - __u16 length; - struct packet data; -}; - -#if LINUX_VERSION_CODE>=0x02032D -#define ctc_protect_busy(dev) \ -s390irq_spin_lock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq) -#define ctc_unprotect_busy(dev) \ -s390irq_spin_unlock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq) - -#define ctc_protect_busy_irqsave(dev,flags) \ -s390irq_spin_lock_irqsave(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags) -#define ctc_unprotect_busy_irqrestore(dev,flags) \ -s390irq_spin_unlock_irqrestore(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags) - -static __inline__ void ctc_set_busy(net_device *dev) -{ - ((struct ctc_priv *)dev->priv)->tbusy=1; - netif_stop_queue(dev); -} - -static __inline__ void ctc_clear_busy(net_device *dev) -{ - ((struct ctc_priv *)dev->priv)->tbusy=0; - netif_start_queue(dev); -} - -static __inline__ int ctc_check_busy(net_device *dev) -{ - eieio(); - return(((struct ctc_priv *)dev->priv)->tbusy); -} - - -static __inline__ void ctc_setbit_busy(int nr,net_device *dev) -{ - set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); - netif_stop_queue(dev); -} - -static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) -{ - clear_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); - if(((struct ctc_priv *)dev->priv)->tbusy==0) - netif_start_queue(dev); -} - -static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) -{ - netif_stop_queue(dev); - return(test_and_set_bit(nr,&((struct ctc_priv *)dev->priv)->tbusy)); -} -#else - -#define ctc_protect_busy(dev) -#define ctc_unprotect_busy(dev) -#define ctc_protect_busy_irqsave(dev,flags) -#define ctc_unprotect_busy_irqrestore(dev,flags) - -static __inline__ void ctc_set_busy(net_device *dev) -{ - dev->tbusy=1; - eieio(); -} - -static __inline__ void ctc_clear_busy(net_device *dev) -{ - dev->tbusy=0; - eieio(); -} - -static __inline__ int ctc_check_busy(net_device *dev) -{ - eieio(); - return(dev->tbusy); -} - - -static __inline__ void ctc_setbit_busy(int nr,net_device *dev) -{ - set_bit(nr,(void *)&dev->tbusy); -} - -static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) -{ - clear_bit(nr,(void *)&dev->tbusy); -} - -static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) -{ - return(test_and_set_bit(nr,(void *)&dev->tbusy)); -} -#endif - - - - - -/* Interrupt handler */ -static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs); -static void ctc_irq_bh(struct channel *ctc); -static void ctc_read_retry (struct channel *ctc); -static void ctc_write_retry (struct channel *ctc); - - -/* Functions for the DEV methods */ -int ctc_probe(net_device *dev); - - -static int ctc_open(net_device *dev); -static void ctc_timer (struct channel *ctc); -static int ctc_release(net_device *dev); -static int ctc_tx(struct sk_buff *skb, net_device *dev); -static int ctc_change_mtu(net_device *dev, int new_mtu); -struct net_device_stats* ctc_stats(net_device *dev); - - -/* - * Channel Routines - * - */ - -static void channel_init(void); -static void channel_scan(void); -static int channel_get(int media, int devno); -static int channel_get_next(int media); -static int channel_free(int media, int devno); -static channel_type_t channel_check_for_type (senseid_t *id); -static void channel_sort(struct devicelist list[], int n); - - -/* - * initialize the channel[].list - */ -static void channel_init(void) -{ - int m; -#ifdef DEBUG - int c; -#endif - - if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){ - channel_scan(); - for (m = 0; m < CHANNEL_MEDIA; m++) { - channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); - channel[m].left = channel[m].count; - } - if (channel[CTC].count == 0 && channel[ESCON].count == 0) - printk(KERN_INFO "channel: no Channel devices recognized\n"); - else - printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n", - channel[CTC].count, channel[ESCON].count); -#ifdef DEBUG - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ - printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", - m, c, channel[m].list[c].devno); - } - } -#endif - } -} - - -/* -* scan for all channels and put the device numbers into the channel[].list -*/ -static void channel_scan(void) -{ - int m; - int c; - int irq; - s390_dev_info_t temp; - - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ - channel[m].list[c].devno = -ENODEV; - } - } - - for (irq = 0; irq < NR_IRQS; irq++) { - /* CTC/A */ - if (channel[CTC].count < MAX_CHANNEL_DEVICES ) { - if (get_dev_info(irq, &temp) == 0 && - channel_check_for_type(&temp.sid_data) == channel_type_ctca) { - channel[CTC].list[channel[CTC].count].devno = temp.devno; - channel[CTC].count++; - } - } - - /* ESCON */ - if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) { - if (get_dev_info(irq, &temp) == 0 && - channel_check_for_type(&temp.sid_data) == channel_type_escon) { - channel[ESCON].list[channel[ESCON].count].devno = temp.devno; - channel[ESCON].count++; - - } - } - } -} - - -/* - * free specific channel from the channel[].list - */ -static int channel_free(int media, int devno) -{ - int i; - - for (i = 0; i < channel[media].count; i++) { - if ((devno == channel[media].list[i].devno) && - ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) { - channel[media].list[i].flag &= ~CHANNEL_IN_USE; - return 0; - } - } - printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); - return -ENODEV; -} - - -/* - * get specific channel from the channel[].list - */ -static int channel_get(int media, int devno) -{ - int i; - - for (i = 0; i < channel[media].count; i++) { - if ((devno == channel[media].list[i].devno) && - ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) { - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); - return -ENODEV; - -} - - -/* - * get the next free channel from the channel[].list - */ -static int channel_get_next(int media) -{ - int i; - - for (i = 0; i < channel[media].count; i++) { - if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno); -#endif - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - return -ENODEV; -} - - -/* - * picks the next free channel from the channel[].list - */ -static int channel_left(int media) -{ - return channel[media].left; -} - - -/* - * defines all devices which are channels - */ -static channel_type_t channel_check_for_type (senseid_t *id) - { - channel_type_t type; - - switch (id->cu_type) { - case 0x3088: - - switch (id->cu_model) { - case 0x08: - type = channel_type_ctca; /* 3088-08 ==> CTCA */ - break; - - case 0x1F: - type = channel_type_escon; /* 3088-1F ==> ESCON channel */ - break; - - case 0x01: /* 3088-01 ==> P390 OSA emulation */ - case 0x60: /* 3088-60 ==> OSA/2 adapter */ - case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */ - case 0x62: /* 3088-62 ==> OSA/D device */ - type = channel_type_unsupported; - break; - - default: - type = channel_type_undefined; - printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model); - } - break; - - default: - type = channel_type_none; - - } - return type; -} - - -/* - * sort the channel[].list - */ -static void channel_sort(struct devicelist list[], int n) -{ - int i; - int sorted = 0; - struct devicelist tmp; - - while (!sorted) { - sorted = 1; - - for (i = 0; i < n-1; i++) { - if (list[i].devno > list[i+1].devno) { - tmp = list[i]; - list[i] = list[i+1]; - list[i+1] = tmp; - sorted = 0; - } - } - } -} - - -/* - * General routines - * - */ - -static int inline extract_channel_id(char *name) -{ - if (name[0] == 'c') - return (name[3]-'0'); - else - return (name[5]-'0'); -} - - -static int inline extract_channel_media(char *name) -{ - if (name[0] == 'c') - return CTC; - else - return ESCON; -} - - -static void ctc_tab_init(void) -{ - int m; - int i; - static int t; - - if (t == 0){ - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (i = 0; i < MAX_ADAPTERS; i++) { - ctc_adapter[m][i].devno[WRITE] = -ENODEV; - ctc_adapter[m][i].devno[READ] = -ENODEV; - } - } - t = 1; - } -} - - -static int ctc_buffer_alloc(struct channel *ctc) { - - struct buffer *p; - struct buffer *q; - - p = kmalloc(sizeof(p), GFP_KERNEL); - if (p == NULL) - return -ENOMEM; - else { - p->next = NULL; - p->packets = 0; - p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); - if (p->block == NULL) { - kfree(p); - return -ENOMEM; - } - } - - if (ctc->free_anchor == NULL) - ctc->free_anchor = p; - else { - q = ctc->free_anchor; - while (q->next != NULL) - q = q->next; - q->next = p; - } - ctc->buffer_count++; - return 0; -} - - -static int ctc_buffer_free(struct channel *ctc) { - - struct buffer *p; - - - if (ctc->free_anchor == NULL) - return -ENOMEM; - - p = ctc->free_anchor; - ctc->free_anchor = p->next; - free_pages((__u32)p->block, 4); - kfree(p); - - return 0; -} - - -static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) { - - struct buffer *p = NULL; - struct buffer *q = NULL; - - if (*from == NULL) - return -ENOMEM; - - p = *from; - *from = p->next; - p->next = NULL; - - if (*to == NULL) - *to = p; - else { - q = *to; - while (q->next != NULL) - q = q->next; - q->next = p; - - } - return 0; -} - - -/* - * ctc_setup function - * this function is called for each ctc= keyword passed into the kernel - * - * valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx - * where n is the channel protocol always 0 - * 0xnnnn is the cu number read - * 0xnnnn is the cu number write - * ctcx can be ctc0 to ctc7 or escon0 to escon7 - */ -#if LINUX_VERSION_CODE>=0x020300 -static int __init ctc_setup(char *dev_name) -#else -__initfunc(void ctc_setup(char *dev_name,int *ints)) -#endif -{ - struct adapterlist tmp; -#if LINUX_VERSION_CODE>=0x020300 - #define CTC_MAX_PARMS 4 - int ints[CTC_MAX_PARMS+1]; - get_options(dev_name,CTC_MAX_PARMS,ints); - #define ctc_setup_return return(1) -#else - #define ctc_setup_return return -#endif - ctc_tab_init(); - - ctc_no_auto = 1; - - if (!strcmp(dev_name,"noauto")) { - printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); - ctc_setup_return; - } - - tmp.devno[WRITE] = -ENODEV; - tmp.devno[READ] = -ENODEV; - - switch (ints[0]) { - - case 3: /* write channel passed */ - tmp.devno[WRITE] = ints[3]; - - case 2: /* read channel passed */ - tmp.devno[READ] = ints[2]; - if (tmp.devno[WRITE] == -ENODEV) - tmp.devno[WRITE] = tmp.devno[READ] + 1; - - case 1: /* protocol type passed */ - tmp.protocol = ints[1]; - if (tmp.protocol == 0) { - break; - } else { - printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name); - ctc_setup_return; - } - break; - - default: - printk(KERN_WARNING "ctc: wrong number of parameter passed\n"); - ctc_setup_return; - } - ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp; -#ifdef DEBUG - printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n", - dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]); -#endif - ctc_setup_return; - -} -#if LINUX_VERSION_CODE>=0x020300 -__setup("ctc=", ctc_setup); -#endif - -/* - * ctc_probe - * this function is called for each channel network device, - * which is defined in the /init/main.c - */ -int ctc_probe(net_device *dev) -{ - int rc; - int c; - int i; - int m; - - struct ctc_priv *privptr; - - /* Only the first time the ctc_probe gets control */ - if (channel_tab_initialized == 0) { - channel_init(); - - - } - - ctc_tab_init(); - - m = extract_channel_media(dev->name); - i = extract_channel_id(dev->name); - - if (channel_left(m) <=1) - return -ENODEV; - - if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV)) - return -ENODEV; - - dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ctc_priv)); - privptr = (struct ctc_priv *) (dev->priv); - - - for (c = 0; c < 2; c++) { - - privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL); - if (privptr->channel[c].devstat == NULL){ - if (i == WRITE) - kfree(privptr->channel[READ].devstat); - return -ENOMEM; - } - memset(privptr->channel[c].devstat, 0, sizeof(devstat_t)); - - if (ctc_no_auto == 0) - ctc_adapter[m][i].devno[c] = channel_get_next(m); - else - ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]); - - if ( ctc_adapter[m][i].devno[c] != -ENODEV){ - rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), - (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, - privptr->channel[c].devstat); - if (rc) { - printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc); - return -EBUSY; - } - } else { - if (i == WRITE) { - free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat); - channel_free(m, ctc_adapter[m][i].devno[READ]); - kfree(privptr->channel[READ].devstat); - } - kfree(privptr->channel[i].devstat); - return -ENODEV; - } - } - - privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ]; - privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]); - privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE]; - privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]); - privptr->protocol = ctc_adapter[m][i].protocol; - channel[m].left = channel[m].left - 2; - - printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n", - dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq, - privptr->channel[WRITE].devno, privptr->channel[WRITE].irq); - - dev->mtu = CTC_DEFAULT_MTU_SIZE; - dev->hard_start_xmit = ctc_tx; - dev->open = ctc_open; - dev->stop = ctc_release; - dev->get_stats = ctc_stats; - dev->change_mtu = ctc_change_mtu; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_SLIP; - dev->tx_queue_len = 100; - dev_init_buffers(dev); - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - - return 0; -} - - -/* - * Interrupt processing - * - */ - -static void inline ccw_check_return_code (net_device *dev, int return_code) -{ - if (return_code != 0) { - switch (return_code) { - case -EBUSY: - printk(KERN_INFO "%s: Busy !\n", dev->name); - break; - case -ENODEV: - printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name); - break; - case -EIO: - printk(KERN_EMERG "%s: Status pending... \n", dev->name); - break; - default: - printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", - dev->name, return_code); - } - } -} - - -static void inline ccw_check_unit_check (net_device *dev, char sense) -{ -#ifdef DEBUG - printk(KERN_INFO "%s: Unit Check with sense code: %02x\n", - dev->name, sense); -#endif - - if (sense & 0x40) { -#ifdef DEBUG - if (sense & 0x01) - printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name); - else - printk(KERN_DEBUG "%s: System reset occurred (remote side)\n", dev->name); -#endif - } else if (sense & 0x20) { - if (sense & 0x04) - printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name); - else - printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name); - } else if (sense & 0x10) { - if (sense & 0x20) - printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name); - else - printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name); - } - -} - - -static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) -{ - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - struct channel *ctc = NULL; - struct ctc_priv *privptr = NULL; - net_device *dev = NULL; - - ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL}, - {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; - - devstat_t *devstat = ((devstat_t *)initparm); - - /* Bypass all 'unsolited interrupts' */ - if (devstat->intparm == 0) { -#ifdef DEBUG - printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n", - devstat->devno, devstat->cstat, devstat->dstat, devstat->flag); -#endif - /* FIXME - find the related intparm!!! No IO outstanding!!!! */ - return; - } - - ctc = (struct channel *) (devstat->intparm); - dev = (net_device *) ctc->dev; - privptr = dev->priv; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n", - dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state); -#endif - - /* Check for good subchannel return code, otherwise error message */ - if (devstat->cstat) { - printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", - dev->name, ctc->devno, devstat->cstat); - return; - } - - - /* Check the reason-code of a unit check */ - if (devstat->dstat & DEV_STAT_UNIT_CHECK) - ccw_check_unit_check(dev, devstat->ii.sense.data[0]); - - - /* State machine to bring the connection up / down and to restart */ - - ctc->last_dstat = devstat->dstat; - - switch (ctc->state) { - - case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */ - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - wake_up(&ctc->wait); /* wake up ctc_release */ - return; - - - case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - - ctc->state = CTC_START_SET_X_MODE; - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; - - - case CTC_START_SET_X_MODE: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) != 0x41 || - (devstat->ii.sense.data[0] & 0x40) != 0x40) { - wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */ - return; - } - } - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - ctc->state = CTC_START_SELECT; - - - case CTC_START_SELECT: - if (!ctc->flag & CTC_WRITE) { - ctc->state = CTC_START_READ_TEST; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - wake_up(&ctc->wait); /* wake up ctc_open (READ) */ - - } else { - ctc->state = CTC_START_WRITE_TEST; - /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ - ctc->ccw[1].count = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags); - if (rc != 0) - ccw_check_return_code(dev, rc); - } - return; - - - case CTC_START_READ_TEST: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_read_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 10*HZ; - add_timer(&ctc->timer); -#ifdef DEBUG - printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); -#endif - } - return; - } - - if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - if ((devstat->dstat & DEV_STAT_ATTENTION) && - (devstat->dstat & DEV_STAT_BUSY)) { - printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name); - } - wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */ - return; - } - - ctc->state = CTC_START_READ; - set_bit(0, (void *)&ctc->IO_active); - - /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ - /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ - - - case CTC_START_READ: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - privptr->stats.rx_errors++; - /* Need protection here cos we are in the read irq */ - /* handler the tbusy is for the write subchannel */ - ctc_protect_busy(dev); - ctc_setbit_busy(TB_RETRY,dev); - ctc_unprotect_busy(dev); - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_read_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 30*HZ; - add_timer(&ctc->timer); - printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name); - } - return; - } - - if(!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - ctc_protect_busy(dev); - ctc_clearbit_busy(TB_RETRY,dev); - ctc_unprotect_busy(dev); - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - - if (ctc->free_anchor != NULL) { - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - } else { - clear_bit(0, (void *)&ctc->IO_active); -#ifdef DEBUG - printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name); -#endif - } - - if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) { - queue_task(&ctc->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - return; - - - case CTC_START_WRITE_TEST: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_write_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 10*HZ; - add_timer(&ctc->timer); -#ifdef DEBUG - printk(KERN_DEBUG "%s: write connection restarted\n",dev->name); -#endif - } - return; - } - - ctc->state = CTC_START_WRITE; - wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ - return; - - - case CTC_START_WRITE: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - privptr->stats.tx_errors += ctc->proc_anchor->packets; -#ifdef DEBUG - printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name); -#endif - } else { - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - privptr->stats.tx_packets += ctc->proc_anchor->packets; - } - - ctc->proc_anchor->block->length = 0; - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - ctc_clearbit_busy(TB_NOBUFFER,dev); - if (ctc->proc_anchor != NULL) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); -#endif - ctc->ccw[1].count = ctc->proc_anchor->block->length; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - dev->trans_start = jiffies; - return; - - } - - if (ctc->free_anchor->block->length != 0) { - if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { - /* set transmission to busy */ - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - ctc_clearbit_busy(TB_TX,dev); -#ifdef DEBUG - printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); -#endif - ctc->ccw[1].count = ctc->proc_anchor->block->length; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - dev->trans_start = jiffies; - return; - } - } - - clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */ - return; - - - default: - printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); - return; - } -} - - -static void ctc_irq_bh (struct channel *ctc) -{ - int rc = 0; - __u16 data_len; - __u32 parm; - - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - struct ctc_priv *privptr; - struct packet *lp; - struct sk_buff *skb; - - dev = (net_device *) ctc->dev; - privptr = (struct ctc_priv *) dev->priv; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state); -#endif - - while (ctc->proc_anchor != NULL) { - - lp = &ctc->proc_anchor->block->data; - - while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) { - data_len = lp->length - PACKET_HEADER_LENGTH; - skb = dev_alloc_skb(data_len); - if (skb) { - memcpy(skb_put(skb, data_len),&lp->data, data_len); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */ - netif_rx(skb); - privptr->stats.rx_packets++; - } else { - privptr->stats.rx_dropped++; - printk(KERN_WARNING "%s: is low on memory\n",dev->name); - } - (__u8 *)lp += lp->length; - } - - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - - if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name); -#endif - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - } - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - } - clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a); - return; -} - - -static void ctc_read_retry (struct channel *ctc) -{ - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - - dev = (net_device *) ctc->dev; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state); -#endif - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; -} - - -static void ctc_write_retry (struct channel *ctc) -{ - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - - dev = (net_device *) ctc->dev; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state); -#endif - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->ccw[1].count = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; -} - - - -/* - * ctc_open - * - */ -static int ctc_open(net_device *dev) -{ - int rc; - int i; - int j; - __u8 flags = 0x00; - __u32 saveflags; - __u32 parm; - struct ctc_priv *privptr; - DECLARE_WAITQUEUE(wait, current); - struct timer_list timer; - - - ctc_set_busy(dev); - - privptr = (struct ctc_priv *) (dev->priv); - - privptr->channel[READ].flag = 0x00; - privptr->channel[WRITE].flag = CTC_WRITE; - - for (i = 0; i < 2; i++) { - for (j = 0; j < CTC_BLOCKS; j++) { - rc = ctc_buffer_alloc(&privptr->channel[i]); - if (rc != 0) - return -ENOMEM; - } - init_waitqueue_head(&privptr->channel[i].wait); - INIT_LIST_HEAD(&privptr->channel[i].tq.list); - privptr->channel[i].tq.sync = 0; - privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh; - privptr->channel[i].tq.data = &privptr->channel[i]; - - privptr->channel[i].dev = dev; - - privptr->channel[i].flag_a = 0; - privptr->channel[i].IO_active = 0; - - privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE; - privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; - privptr->channel[i].ccw[0].count = 0; - privptr->channel[i].ccw[0].cda = NULL; - if (i == READ) { - privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ; - privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI; - privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */ - privptr->channel[i].ccw[1].cda = NULL; - } else { - privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE; - privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC; - privptr->channel[i].ccw[1].count = 0; - privptr->channel[i].ccw[1].cda = NULL; - } - privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */ - privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI; - privptr->channel[i].ccw[2].count = 0; - privptr->channel[i].ccw[2].cda = NULL; - - privptr->channel[i].flag &= ~CTC_TIMER; - init_timer(&timer); - timer.function = (void *)ctc_timer; - timer.data = (__u32)&privptr->channel[i]; - timer.expires = jiffies + 150*HZ; /* time to connect with the remote side */ - add_timer(&timer); - - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - parm = (unsigned long) &privptr->channel[i]; - privptr->channel[i].state = CTC_START_HALT_IO; - rc = halt_IO(privptr->channel[i].irq, parm, flags); - add_wait_queue(&privptr->channel[i].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - schedule(); - remove_wait_queue(&privptr->channel[i].wait, &wait); - if(rc != 0) - ccw_check_return_code(dev, rc); - if((privptr->channel[i].flag & CTC_TIMER) == 0x00) - del_timer(&timer); - } - - if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & - ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || - (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n", - dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); -#endif - printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name); - - for (i = 0; i < 2; i++) { - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - parm = (unsigned long) &privptr->channel[i]; - privptr->channel[i].state = CTC_STOP; - rc = halt_IO(privptr->channel[i].irq, parm, flags); - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - for (j = 0; j < CTC_BLOCKS; j++) - ctc_buffer_free(&privptr->channel[i]); - } - return -EIO; - } - - printk(KERN_INFO "%s: connected with remote side\n",dev->name); - ctc_clear_busy(dev); - return 0; -} - - -static void ctc_timer (struct channel *ctc) -{ -#ifdef DEBUG - net_device *dev; - - dev = (net_device *) ctc->dev; - printk(KERN_DEBUG "%s: timer return\n" ,dev->name); -#endif - ctc->flag |= CTC_TIMER; - wake_up(&ctc->wait); - return; -} - -/* - * ctc_release - * - */ -static int ctc_release(net_device *dev) -{ - int rc; - int i; - int j; - __u8 flags = 0x00; - __u32 saveflags; - __u32 parm; - struct ctc_priv *privptr; - DECLARE_WAITQUEUE(wait, current); - - privptr = (struct ctc_priv *) dev->priv; - - ctc_protect_busy_irqsave(dev,saveflags); - ctc_setbit_busy(TB_STOP,dev); - ctc_unprotect_busy_irqrestore(dev,flags); - for (i = 0; i < 2; i++) { - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - privptr->channel[i].state = CTC_STOP; - parm = (__u32) &privptr->channel[i]; - rc = halt_IO (privptr->channel[i].irq, parm, flags ); - add_wait_queue(&privptr->channel[i].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - schedule(); - remove_wait_queue(&privptr->channel[i].wait, &wait); - if (rc != 0) { - ccw_check_return_code(dev, rc); - } - - for (j = 0; j < CTC_BLOCKS; j++) { - ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor); - ctc_buffer_free(&privptr->channel[i]); - } - } - - if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & - ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n", - dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); - return -EIO; - } - - return 0; -} - - -/* - * ctc_tx - * - * - */ -static int ctc_tx(struct sk_buff *skb, net_device *dev) -{ - int rc=0,rc2; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - struct ctc_priv *privptr; - struct packet *lp; - - - privptr = (struct ctc_priv *) (dev->priv); - - if (skb == NULL) { - printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name); - privptr->stats.tx_dropped++; - return -EIO; - } - - s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags); - if (ctc_check_busy(dev)) { - rc=-EBUSY; - goto Done; - } - - if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */ - rc=-EBUSY; - goto Done; - } - - if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: early swap\n", dev->name); -#endif - - ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor); - if (privptr->channel[WRITE].free_anchor == NULL){ - ctc_setbit_busy(TB_NOBUFFER,dev); - rc=-EBUSY; - goto Done2; - } - } - - if (privptr->channel[WRITE].free_anchor->block->length == 0) { - privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; - privptr->channel[WRITE].free_anchor->packets = 0; - } - - - (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length; - privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; - lp->length = skb->len + PACKET_HEADER_LENGTH; - lp->type = 0x0800; - lp->unused = 0; - memcpy(&lp->data, skb->data, skb->len); - (__u8 *) lp += lp->length; - lp->length = 0; - dev_kfree_skb(skb); - privptr->channel[WRITE].free_anchor->packets++; - - if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) { - ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor); - privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length; - privptr->channel[WRITE].ccw[1].cda = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block); - parm = (__u32) &privptr->channel[WRITE]; - rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags ); - if (rc2 != 0) - ccw_check_return_code(dev, rc2); - dev->trans_start = jiffies; - } - if (privptr->channel[WRITE].free_anchor == NULL) - ctc_setbit_busy(TB_NOBUFFER,dev); -Done2: - ctc_clearbit_busy(TB_TX,dev); -Done: - s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags); - return(rc); -} - - -/* - * ctc_change_mtu - * - * S/390 can handle MTU sizes from 576 to 32760 for VM, VSE - * 576 to 65527 for OS/390 - * - */ -static int ctc_change_mtu(net_device *dev, int new_mtu) -{ - if ((new_mtu < 576) || (new_mtu > 65528)) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} - - -/* - * ctc_stats - * - */ -struct net_device_stats *ctc_stats(net_device *dev) -{ - struct ctc_priv *privptr; - - privptr = dev->priv; - return &privptr->stats; -} - - -/* Module code goes here */ - -/* - free_irq(privptr->channel[i].irq, privptr->channel[i].devstat); - kfree(privptr->channel[i].devstat); - -*/ -/* --- This is the END my friend --- */ diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctcmain.c linux/drivers/s390/net/ctcmain.c --- v2.4.3/linux/drivers/s390/net/ctcmain.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/net/ctcmain.c Wed Apr 11 19:02:28 2001 @@ -1,12 +1,12 @@ /* - * $Id: ctcmain.c,v 1.11 2000/12/15 19:34:54 bird Exp $ + * $Id: ctcmain.c,v 1.17 2001/01/23 14:23:51 felfert Exp $ * * CTC / ESCON network driver * - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * Fixes by : Jochen Röhrig (roehrig@de.ibm.com) - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * Documentation used: * - Principles of Operation (IBM doc#: SA22-7201-06) @@ -36,6 +36,26 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: ctcmain.c,v $ + * Revision 1.17 2001/01/23 14:23:51 felfert + * Added ctc based tty. + * + * Revision 1.16 2001/01/18 16:10:53 felfert + * Added fixes by acme@conectiva.com.br. + * + * Revision 1.15 2001/01/12 15:40:11 felfert + * Fixed ITPM# PL030052IME (Unitchecks when using real escon). + * + * Revision 1.14 2001/01/11 17:43:52 felfert + * Fixed ITPM# PL030051IME (Initialization of escon). + * + * Revision 1.13 2001/01/11 16:40:26 smolinsk + * resolved name space conflict with LVM and renamed + * dev_info_t to s390_dev_info_t + * worked around a bug in OSA microcode by stepping back to 2k IDALS in idals.c + * + * Revision 1.12 2000/12/27 09:40:45 tonn + * upgrade to test12 + * * Revision 1.11 2000/12/15 19:34:54 bird * struct ctc_priv_t: set type of tbusy to "unsigned long" * @@ -89,8 +109,6 @@ #include <linux/string.h> #include <linux/proc_fs.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> #include <linux/ip.h> #include <linux/if_arp.h> #include <linux/tcp.h> @@ -112,6 +130,7 @@ #include <asm/irq.h> +#include "ctctty.h" #include "fsm.h" #ifdef MODULE @@ -142,7 +161,8 @@ #define CTC_PROTO_S390 0 #define CTC_PROTO_LINUX 1 -#define CTC_PROTO_MAX 1 +#define CTC_PROTO_LINUX_TTY 2 +#define CTC_PROTO_MAX 2 #define CTC_BUFSIZE_LIMIT 65535 #define CTC_BUFSIZE_DEFAULT 32768 @@ -186,19 +206,13 @@ typedef enum channel_types channel_type_t; -static int ctc_no_auto; +static int ctc_no_auto = 0; /** * If running on 64 bit, this must be changed. XXX Why? (bird) */ typedef unsigned long intparm_t; -#if LINUX_VERSION_CODE < 0x020300 -typedef struct device net_device; -#else -typedef struct net_device net_device; -#endif - /** * Definition of a per device parameter block */ @@ -211,7 +225,7 @@ char name[MAX_PARAM_NAME_LEN]; } param; -static param *params; +static param *params = NULL; typedef struct { unsigned long maxmulti; @@ -248,7 +262,7 @@ __u32 flags; /** - * The protocol of this channel (currently always 0) + * The protocol of this channel */ __u16 protocol; @@ -342,7 +356,7 @@ /** * Linked list of all detected channels. */ -static channel *channels; +static channel *channels = NULL; typedef struct ctc_priv_t { struct net_device_stats stats; @@ -353,6 +367,10 @@ * The finite state machine of this interface. */ fsm_instance *fsm; + /** + * The protocol of this device + */ + __u16 protocol; channel *channel[2]; struct proc_dir_entry *proc_dentry; struct proc_dir_entry *proc_stat_entry; @@ -406,8 +424,8 @@ * Print Banner. */ static void print_banner(void) { - static int printed; - char vbuf[] = "$Revision: 1.11 $"; + static int printed = 0; + char vbuf[] = "$Revision: 1.17 $"; char *version = vbuf; if (printed) @@ -796,7 +814,10 @@ dev_kfree_skb(skb); goto again; } - netif_rx(skb2); + if (ch->protocol == CTC_PROTO_LINUX_TTY) + ctc_tty_netif_rx(skb2); + else + netif_rx(skb2); privptr->stats.rx_packets++; privptr->stats.rx_bytes += skb2->len; /** @@ -805,7 +826,10 @@ skb_pull(skb, header->length); skb_put(skb, LL_HEADER_LENGTH); } else { - netif_rx(skb); + if (ch->protocol == CTC_PROTO_LINUX_TTY) + ctc_tty_netif_rx(skb); + else + netif_rx(skb); privptr->stats.rx_packets++; privptr->stats.rx_bytes += skb->len; } @@ -892,8 +916,10 @@ ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch); } + } else if (sense & SNS0_CMD_REJECT) { + printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno); } else if (sense == 0) { - printk(KERN_DEBUG "ch-%04x: Unit check\n", ch->devno); + printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch); } else { printk(KERN_WARNING @@ -1078,15 +1104,15 @@ fsm_deltimer(&ch->timer); if (len < 8) { - printk(KERN_WARNING "%s: got packet with length < 8\n", - dev->name); + printk(KERN_WARNING "%s: got packet with length %d < 8\n", + dev->name, len); privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; } if (len > ch->max_bufsize) { - printk(KERN_WARNING "%s: got packet with length > %d\n", - dev->name, ch->max_bufsize); + printk(KERN_WARNING "%s: got packet with length %d > %d\n", + dev->name, len, ch->max_bufsize); privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; @@ -1764,14 +1790,18 @@ channel **c = &channels; channel *ch; char name[10]; - int ret = -1; - if ((ch = (channel *)kmalloc(sizeof(channel), GFP_KERNEL)) == NULL) - goto out; + if ((ch = (channel *)kmalloc(sizeof(channel), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); + return -1; + } memset(ch, 0, sizeof(channel)); if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 5, - GFP_KERNEL|GFP_DMA)) == NULL) - goto out_ch; + GFP_KERNEL|GFP_DMA)) == NULL) { + kfree(ch); + printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); + return -1; + } /** * "static" ccws are used in the following way: @@ -1804,12 +1834,19 @@ ch->fsm = init_fsm(name, ch_state_names, ch_event_names, NR_CH_STATES, NR_CH_EVENTS, ch_fsm, CH_FSM_LEN, GFP_KERNEL); - if (ch->fsm == NULL) - goto out_ccw; + if (ch->fsm == NULL) { + printk(KERN_WARNING "ctc: Could not create FSM in add_channel\n"); + kfree(ch); + return -1; + } fsm_newstate(ch->fsm, CH_STATE_IDLE); if ((ch->devstat = (devstat_t*)kmalloc(sizeof(devstat_t), GFP_KERNEL)) - == NULL) - goto out_ccw; + == NULL) { + printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); + kfree_fsm(ch->fsm); + kfree(ch); + return -1; + } memset(ch->devstat, 0, sizeof(devstat_t)); while (*c && ((*c)->devno < devno)) c = &(*c)->next; @@ -1817,8 +1854,10 @@ printk(KERN_DEBUG "ctc: add_channel: device %04x already in list\n", (*c)->devno); - ret = 0; - goto out_devstat; + kfree(ch->devstat); + kfree_fsm(ch->fsm); + kfree(ch); + return 0; } fsm_settimer(ch->fsm, &ch->timer); skb_queue_head_init(&ch->io_queue); @@ -1826,16 +1865,6 @@ ch->next = *c; *c = ch; return 0; -out_devstat: - kfree(ch->devstat); -out_ccw: - kfree(ch->ccw); -out_ch: - kfree(ch); -out: - if (ret) - printk(KERN_WARNING "ctc: Out of memory in add_channel\n"); - return ret; } /** @@ -1846,9 +1875,9 @@ */ static void channel_scan(int print_result) { - int irq; - int nr_escon = 0; - int nr_ctca = 0; + int irq; + int nr_escon = 0; + int nr_ctca = 0; s390_dev_info_t di; for (irq = 0; irq < NR_IRQS; irq++) { @@ -2284,6 +2313,8 @@ if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) { int l = skb->len + LL_HEADER_LENGTH; + if (ch->type == channel_type_escon) + return -EBUSY; spin_lock_irqsave(&ch->collect_lock, saveflags); if (ch->collect_len + l > ch->max_bufsize - 2) rc = -EBUSY; @@ -3141,7 +3172,7 @@ * * @param dev Pointer to net_device to be initialized. * - * @return 0 on success, !0 on failure. + * @returns 0 on success, !0 on failure. */ int ctc_probe(net_device *dev) { @@ -3190,6 +3221,7 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(ctc_priv)); privptr = (ctc_priv *)dev->priv; + privptr->protocol = proto; privptr->proc_dentry = (struct proc_dir_entry *) (((char *)privptr) + sizeof(ctc_priv)); privptr->proc_stat_entry = (struct proc_dir_entry *) @@ -3295,6 +3327,7 @@ void cleanup_module(void) { channel *c = channels; + ctc_tty_cleanup(); /* we are called if all interfaces are down only, so no need * to bother around with locking stuff */ @@ -3313,7 +3346,10 @@ privptr->channel[WRITE]->devstat); kfree_fsm(privptr->channel[READ]->fsm); kfree_fsm(privptr->channel[WRITE]->fsm); - unregister_netdev(nd); + if (privptr->protocol != CTC_PROTO_LINUX_TTY) + unregister_netdev(nd); + else + ctc_tty_unregister_netdev(nd); kfree_fsm(privptr->fsm); privptr->channel[READ]->netdev = NULL; privptr->channel[WRITE]->netdev = NULL; @@ -3345,6 +3381,7 @@ int cnt[2]; int itype; int activated; + int ret = 0; param *par; print_banner(); @@ -3359,10 +3396,11 @@ #endif activated = 0; par = params; + ctc_tty_init(); for (itype = 0; itype < 2; itype++) { net_device *dev = NULL; char *bname = (itype) ? "escon" : "ctc"; - int nlen = strlen(bname); + cnt[itype] = 0; do { dev = kmalloc(sizeof(net_device) @@ -3370,8 +3408,10 @@ + 11 /* name + zero */ #endif , GFP_KERNEL); - if (!dev) - return -ENOMEM; + if (!dev) { + ret = -ENOMEM; + break; + } memset(dev, 0, sizeof(net_device)); #if LINUX_VERSION_CODE < 0x020300 dev->name = (unsigned char *)dev + sizeof(net_device); @@ -3386,10 +3426,10 @@ if (isdigit(*p)) break; if (p && *p) { + int it = (strncmp(dev->name, "escon", 5)) ? 1 : 0; n = simple_strtoul(p, NULL, 0); - if (n >= cnt[itype] && - (!strncmp(par->name, bname, nlen))) - cnt[itype] = n + 1; + if (n >= cnt[it]) + cnt[it] = n + 1; } } else { if (ctc_no_auto) { @@ -3406,6 +3446,7 @@ __FUNCTION__, dev->name); #endif if (ctc_probe(dev) == 0) { + ctc_priv *privptr = (ctc_priv *)dev->priv; #ifdef DEBUG printk(KERN_DEBUG "ctc: %s(): probing succeeded\n", @@ -3413,28 +3454,49 @@ printk(KERN_DEBUG "ctc: %s(): registering device %s\n", __FUNCTION__, dev->name); +#endif + if (privptr->protocol != CTC_PROTO_LINUX_TTY) { + if (register_netdev(dev) != 0) { + printk(KERN_WARNING + "ctc: Couldn't register netdev %s\n", + dev->name); + free_irq(privptr->channel[READ]->irq, + privptr->channel[READ]->devstat); + free_irq(privptr->channel[WRITE]->irq, + privptr->channel[WRITE]->devstat); + channel_free(privptr->channel[READ]); + channel_free(privptr->channel[WRITE]); + kfree(dev->priv); + kfree(dev); + } else { +#ifdef DEBUG + printk(KERN_DEBUG + "ctc: %s(): register succeed\n", + __FUNCTION__); #endif - if (register_netdev(dev) != 0) { - ctc_priv *privptr = - (ctc_priv *)dev->priv; - printk(KERN_WARNING - "ctc: Couldn't register %s\n", - dev->name); - free_irq(privptr->channel[READ]->irq, - privptr->channel[READ]->devstat); - free_irq(privptr->channel[WRITE]->irq, - privptr->channel[WRITE]->devstat); - channel_free(privptr->channel[READ]); - channel_free(privptr->channel[WRITE]); - kfree(dev->priv); - kfree(dev); + activated++; + } } else { + if (ctc_tty_register_netdev(dev) != 0) { + printk(KERN_WARNING + "ctc: Couldn't register ttydev %s\n", + dev->name); + free_irq(privptr->channel[READ]->irq, + privptr->channel[READ]->devstat); + free_irq(privptr->channel[WRITE]->irq, + privptr->channel[WRITE]->devstat); + channel_free(privptr->channel[READ]); + channel_free(privptr->channel[WRITE]); + kfree(dev->priv); + kfree(dev); + } else { #ifdef DEBUG - printk(KERN_DEBUG - "ctc: %s(): register succeed\n", - __FUNCTION__); + printk(KERN_DEBUG + "ctc: %s(): register succeed\n", + __FUNCTION__); #endif - activated++; + activated++; + } } } else { @@ -3446,13 +3508,15 @@ kfree(dev); dev = NULL; } - } while (dev); + } while (dev && (ret == 0)); } if (!activated) { printk(KERN_WARNING "ctc: No devices registered\n"); - return -ENODEV; + ret = -ENODEV; } - return 0; + if (ret) + ctc_tty_cleanup(); + return ret; } #ifndef MODULE diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctctty.c linux/drivers/s390/net/ctctty.c --- v2.4.3/linux/drivers/s390/net/ctctty.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/net/ctctty.c Wed Apr 11 19:02:28 2001 @@ -0,0 +1,1139 @@ +/* + * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $ + * + * CTC / ESCON network driver, tty interface. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.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, 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. + * + */ + +#define __NO_VERSION__ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/serial_reg.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#ifdef CONFIG_DEVFS_FS +# include <linux/devfs_fs_kernel.h> +#endif +#include "ctctty.h" +#include <net/dst.h> + +#define CTC_TTY_MAJOR 43 +#define CTC_TTY_MAX_DEVICES 64 + +#define CTC_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */ +#define CTC_ASYNC_INITIALIZED 0x80000000 /* port was initialized */ +#define CTC_ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device active */ +#define CTC_ASYNC_CLOSING 0x08000000 /* Serial port is closing */ +#define CTC_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define CTC_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */ +#define CTC_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */ +#define CTC_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */ +#define CTC_TTY_XMIT_SIZE 1024 /* Default bufsize for write */ +#define CTC_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */ +#define CTC_SERIAL_TYPE_NORMAL 1 + +/* Private data (similar to async_struct in <linux/serial.h>) */ +typedef struct { + int magic; + int flags; /* defined in tty.h */ + int x_char; /* xon/xoff character */ + int mcr; /* Modem control register */ + int msr; /* Modem status register */ + int lsr; /* Line status register */ + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + net_device *netdev; + struct sk_buff_head tx_queue; /* transmit queue */ + struct sk_buff_head rx_queue; /* receive queue */ + struct tty_struct *tty; /* Pointer to corresponding tty */ + struct termios normal_termios; /* For saving termios structs */ + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + struct semaphore write_sem; + struct tq_struct tq; +} ctc_tty_info; + +/* Description of one CTC-tty */ +typedef struct { + int refcount; /* Number of opens */ + struct tty_driver ctc_tty_device; /* tty-device */ + struct tty_struct *modem_table[CTC_TTY_MAX_DEVICES]; + struct termios *modem_termios[CTC_TTY_MAX_DEVICES]; + struct termios *modem_termios_locked[CTC_TTY_MAX_DEVICES]; + ctc_tty_info info[CTC_TTY_MAX_DEVICES]; /* Private data */ +} ctc_tty_driver; + +static ctc_tty_driver *driver; + +/* Leave this unchanged unless you know what you do! */ +#define MODEM_PARANOIA_CHECK +#define MODEM_DO_RESTART + +#define CTC_TTY_NAME "ttyZ" + +#ifdef CONFIG_DEVFS_FS +static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d"; +#else +static char *ctc_ttyname = CTC_TTY_NAME; +#endif + +char *ctc_tty_revision = "$Revision: 1.1 $"; + +/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb() + * to stuff incoming data directly into a tty's flip-buffer. If the + * flip buffer is full, the packet gets queued up. + * + * Return: + * 1 = Success + * 0 = Failure, data has to be buffered and later processed by + * ctc_tty_readmodem(). + */ +static int +ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb) +{ + int c; + int len; + struct tty_struct *tty; + + if ((tty = info->tty)) { + if (info->mcr & UART_MCR_RTS) { + c = TTY_FLIPBUF_SIZE - tty->flip.count; + len = skb->len; + if (c >= len) { + memcpy(tty->flip.char_buf_ptr, skb->data, len); + tty->flip.count += len; + tty->flip.char_buf_ptr += len; + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + queue_task(&tty->flip.tqueue, &tq_timer); + kfree_skb(skb); + return 1; + } + } + } + return 0; +} + +/* ctc_tty_readmodem() is called periodically from within timer-interrupt. + * It tries getting received data from the receive queue an stuff it into + * the tty's flip-buffer. + */ +static int +ctc_tty_readmodem(ctc_tty_info *info) +{ + int ret = 0; + struct tty_struct *tty; + + if ((tty = info->tty)) { + if (info->mcr & UART_MCR_RTS) { + int c = TTY_FLIPBUF_SIZE - tty->flip.count; + struct sk_buff *skb; + + if ((c > 0) && (skb = skb_dequeue(&info->rx_queue))) { + int len = skb->len; + if (len > c) + len = c; + memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len); + tty->flip.count += len; + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + queue_task(&tty->flip.tqueue, &tq_timer); + if (skb->len) { + skb_queue_head(&info->rx_queue, skb); + ret = 1; + } else + kfree_skb(skb); + } + } + } + return ret; +} + +void +ctc_tty_netif_rx(struct sk_buff *skb) +{ + int i; + ctc_tty_info *info = NULL; + + if (!skb) + return; + if (!skb->dev) { + dev_kfree_skb(skb); + return; + } + for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) + if (driver->info[i].netdev == skb->dev) { + info = &driver->info[i]; + break; + } + if (!info) { + dev_kfree_skb(skb); + return; + } + skb_pull(skb, sizeof(int)); + /* Try to deliver directly via tty-flip-buf if queue is empty */ + if (skb_queue_empty(&info->rx_queue)) + if (ctc_tty_try_read(info, skb)) + return; + /* Direct deliver failed or queue wasn't empty. + * Queue up for later dequeueing via timer-irq. + */ + skb_queue_tail(&info->rx_queue, skb); + /* Schedule dequeuing */ + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void +ctc_tty_dstfail(struct sk_buff *skb) { + if (!skb) + return; + dev_kfree_skb(skb); + return; +} + +static struct dst_entry dst_e; +static struct dst_ops dst_o; + +static int +ctc_tty_tint(ctc_tty_info * info) +{ + struct sk_buff *skb = skb_dequeue(&info->tx_queue); + int rc; + int l; + char c; + + if (!skb) + return 0; + if (!info->netdev) { + kfree(skb); + return 0; + } + skb->dst = &dst_e; + l = skb->len; + c = *(skb->data); + rc = info->netdev->hard_start_xmit(skb, info->netdev); +printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c); + if (rc) { + skb_queue_head(&info->tx_queue, skb); + return 1; + } else { + struct tty_struct *tty = info->tty; + info->lsr |= UART_LSR_TEMT; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + return (skb_queue_empty(&info->tx_queue) ? 0 : 1); +} + +/************************************************************ + * + * Modem-functions + * + * mostly "stolen" from original Linux-serial.c and friends. + * + ************************************************************/ + +static inline int +ctc_tty_paranoia_check(ctc_tty_info * info, kdev_t device, const char *routine) +{ +#ifdef MODEM_PARANOIA_CHECK + if (!info) { + printk(KERN_WARNING "ctc_tty: null info_struct for (%d, %d) in %s\n", + MAJOR(device), MINOR(device), routine); + return 1; + } + if (info->magic != CTC_ASYNC_MAGIC) { + printk(KERN_WARNING "ctc_tty: bad magic for info struct (%d, %d) in %s\n", + MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} + +static void +ctc_tty_change_speed(ctc_tty_info * info) +{ + unsigned int cflag; + unsigned int quot; + int i; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + + quot = i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 2) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (quot) { + info->mcr |= UART_MCR_DTR; + } else { + info->mcr &= ~UART_MCR_DTR; + return; + } + + /* CTS flow control flag and modem status interrupts */ + if (cflag & CRTSCTS) { + info->flags |= CTC_ASYNC_CTS_FLOW; + } else + info->flags &= ~CTC_ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~CTC_ASYNC_CHECK_CD; + else { + info->flags |= CTC_ASYNC_CHECK_CD; + } +} + +static int +ctc_tty_startup(ctc_tty_info * info) +{ + if (info->flags & CTC_ASYNC_INITIALIZED) + return 0; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "starting up %s%d ...\n", CTC_TTY_NAME, info->line); +#endif + /* + * Now, initialize the UART + */ + info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + /* + * and set the speed of the serial port + */ + ctc_tty_change_speed(info); + + info->flags |= CTC_ASYNC_INITIALIZED; + info->msr |= (UART_MSR_DSR | UART_MSR_CTS); + info->netdev->open(info->netdev); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void +ctc_tty_shutdown(ctc_tty_info * info) +{ + if (!(info->flags & CTC_ASYNC_INITIALIZED)) + return; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line); +#endif + info->msr &= ~UART_MSR_RI; + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); + } + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + info->netdev->stop(info->netdev); + skb_queue_purge(&info->tx_queue); + skb_queue_purge(&info->rx_queue); + info->flags &= ~CTC_ASYNC_INITIALIZED; +} + +/* ctc_tty_write() is the main send-routine. It is called from the upper + * levels within the kernel to perform sending data. Depending on the + * online-flag it either directs output to the at-command-interpreter or + * to the lower level. Additional tasks done here: + * - If online, check for escape-sequence (+++) + * - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes. + * - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed. + * - If dialing, abort dial. + */ +static int +ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count) +{ + int c; + int total = 0; + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write")) + return 0; + if (!tty) + return 0; + if (!info->netdev) + return -ENODEV; + if (from_user) + down(&info->write_sem); + while (1) { + struct sk_buff *skb; + int skb_res; + + c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE; + if (c <= 0) + break; + + skb_res = info->netdev->hard_header_len + sizeof(int); + skb = dev_alloc_skb(skb_res + c); + if (!skb) { + printk(KERN_WARNING + "ctc_tty: Out of memory in %s%d write\n", + CTC_TTY_NAME, info->line); + break; + } + skb_reserve(skb, skb_res); + if (from_user) + copy_from_user(skb_put(skb, c), buf, c); + else + memcpy(skb_put(skb, c), buf, c); + skb_queue_tail(&info->tx_queue, skb); + buf += c; + total += c; + count -= c; + } + if (skb_queue_len(&info->tx_queue)) { + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + if (from_user) + up(&info->write_sem); + return total; +} + +static int +ctc_tty_write_room(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write_room")) + return 0; + return CTC_TTY_XMIT_SIZE; +} + +static int +ctc_tty_chars_in_buffer(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_chars_in_buffer")) + return 0; + return 0; +} + +static void +ctc_tty_flush_buffer(struct tty_struct *tty) +{ + ctc_tty_info *info; + unsigned long flags; + + save_flags(flags); + cli(); + if (!tty) { + restore_flags(flags); + return; + } + info = (ctc_tty_info *) tty->driver_data; + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_buffer")) { + restore_flags(flags); + return; + } + skb_queue_purge(&info->tx_queue); + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); +} + +static void +ctc_tty_flush_chars(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars")) + return; + if (skb_queue_len(&info->tx_queue)) { + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +/* + * ------------------------------------------------------------ + * ctc_tty_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void +ctc_tty_throttle(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle")) + return; + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + info->mcr &= ~UART_MCR_RTS; +} + +static void +ctc_tty_unthrottle(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle")) + return; + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + info->mcr |= UART_MCR_RTS; +} + +/* + * ------------------------------------------------------------ + * ctc_tty_ioctl() and friends + * ------------------------------------------------------------ + */ + +/* + * ctc_tty_get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows RS485 driver to be written in user space. + */ +static int +ctc_tty_get_lsr_info(ctc_tty_info * info, uint * value) +{ + u_char status; + uint result; + ulong flags; + + save_flags(flags); + cli(); + status = info->lsr; + restore_flags(flags); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + put_user(result, (uint *) value); + return 0; +} + + +static int +ctc_tty_get_ctc_tty_info(ctc_tty_info * info, uint * value) +{ + u_char control, + status; + uint result; + ulong flags; + + control = info->mcr; + save_flags(flags); + cli(); + status = info->msr; + restore_flags(flags); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + put_user(result, (uint *) value); + return 0; +} + +static int +ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value) +{ + uint arg; + + get_user(arg, (uint *) value); + switch (cmd) { + case TIOCMBIS: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME, + info->line); +#endif + if (arg & TIOCM_RTS) { + info->mcr |= UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr |= UART_MCR_DTR; + } + break; + case TIOCMBIC: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME, + info->line); +#endif + if (arg & TIOCM_RTS) { + info->mcr &= ~UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr &= ~UART_MCR_DTR; + } + break; + case TIOCMSET: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMSET\n", CTC_TTY_NAME, + info->line); +#endif + info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; + } + return 0; +} + +static int +ctc_tty_ioctl(struct tty_struct *tty, struct file *file, + uint cmd, ulong arg) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + int error; + int retval; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_ioctl")) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line); +#endif + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line); +#endif + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TIOCGSOFTCAR: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); + return 0; + case TIOCSSOFTCAR: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); + if (error) + return error; + get_user(arg, (ulong *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCMGET\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + return ctc_tty_get_ctc_tty_info(info, (uint *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint)); + if (error) + return error; + return ctc_tty_set_ctc_tty_info(info, cmd, (uint *) arg); + case TIOCSERGETLSR: /* Get line status register */ +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME, + info->line); +#endif + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + else + return ctc_tty_get_lsr_info(info, (uint *) arg); + default: +#ifdef CTC_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd, + CTC_TTY_NAME, info->line); +#endif + return -ENOIOCTLCMD; + } + return 0; +} + +static void +ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + + if (!old_termios) + ctc_tty_change_speed(info); + else { + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + ctc_tty_change_speed(info); + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + } + } +} + +/* + * ------------------------------------------------------------ + * ctc_tty_open() and friends + * ------------------------------------------------------------ + */ +static int +ctc_tty_block_til_ready(struct tty_struct *tty, struct file *filp, ctc_tty_info *info) +{ + DECLARE_WAITQUEUE(wait, NULL); + int do_clocal = 0; + unsigned long flags; + int retval; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & CTC_ASYNC_CLOSING)) { + if (info->flags & CTC_ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef MODEM_DO_RESTART + if (info->flags & CTC_ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= CTC_ASYNC_NORMAL_ACTIVE; + return 0; + } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * ctc_tty_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_block_til_ready before block: %s%d, count = %d\n", + CTC_TTY_NAME, info->line, info->count); +#endif + save_flags(flags); + cli(); + if (!(tty_hung_up_p(filp))) + info->count--; + restore_flags(flags); + info->blocked_open++; + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & CTC_ASYNC_INITIALIZED)) { +#ifdef MODEM_DO_RESTART + if (info->flags & CTC_ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & CTC_ASYNC_CLOSING) && + (do_clocal || (info->msr & UART_MSR_DCD))) { + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_block_til_ready blocking: %s%d, count = %d\n", + CTC_TTY_NAME, info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_block_til_ready after blocking: %s%d, count = %d\n", + CTC_TTY_NAME, info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= CTC_ASYNC_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int +ctc_tty_open(struct tty_struct *tty, struct file *filp) +{ + ctc_tty_info *info; + int retval, + line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if (line < 0 || line > CTC_TTY_MAX_DEVICES) + return -ENODEV; + info = &driver->info[line]; + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_open")) + return -ENODEV; + if (!info->netdev) + return -ENODEV; +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name, + info->line, info->count); +#endif + info->count++; + tty->driver_data = info; + info->tty = tty; + /* + * Start up serial port + */ + retval = ctc_tty_startup(info); + if (retval) { +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open return after startup\n"); +#endif + return retval; + } + retval = ctc_tty_block_til_ready(tty, filp, info); + if (retval) { +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n"); +#endif + return retval; + } + if ((info->count == 1) && (info->flags & CTC_ASYNC_SPLIT_TERMIOS)) { + *tty->termios = info->normal_termios; + ctc_tty_change_speed(info); + } +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_open %s%d successful...\n", CTC_TTY_NAME, info->line); +#endif + return 0; +} + +static void +ctc_tty_close(struct tty_struct *tty, struct file *filp) +{ + ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; + ulong flags; + ulong timeout; + + if (!info || ctc_tty_paranoia_check(info, tty->device, "ctc_tty_close")) + return; + save_flags(flags); + cli(); + if (tty_hung_up_p(filp)) { + restore_flags(flags); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n"); +#endif + return; + } + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n", + CTC_TTY_NAME, info->line, info->count); + info->count = 0; + } + if (info->count) { + restore_flags(flags); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n"); +#endif + return; + } + info->flags |= CTC_ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & CTC_ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + + tty->closing = 1; + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + if (info->flags & CTC_ASYNC_INITIALIZED) { + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + timeout = jiffies + HZ; + while (!(info->lsr & UART_LSR_TEMT)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(20); + if (time_after(jiffies,timeout)) + break; + } + } + ctc_tty_shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + info->tty = 0; + tty->closing = 0; + if (info->blocked_open) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(50); + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +#ifdef CTC_DEBUG_MODEM_OPEN + printk(KERN_DEBUG "ctc_tty_close normal exit\n"); +#endif +} + +/* + * ctc_tty_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void +ctc_tty_hangup(struct tty_struct *tty) +{ + ctc_tty_info *info = (ctc_tty_info *)tty->driver_data; + + if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup")) + return; + ctc_tty_shutdown(info); + info->count = 0; + info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE; + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + + +/* + * For all online tty's, try sending data to + * the lower levels. + */ +static void +ctc_tty_task(ctc_tty_info *info) +{ + int again; + + again = ctc_tty_tint(info); + again |= ctc_tty_readmodem(info); + if (again) { + queue_task(&info->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +int +ctc_tty_init(void) +{ + int i; + ctc_tty_info *info; + struct tty_driver *device; + + dst_e.ops = &dst_o; + dst_o.link_failure = ctc_tty_dstfail; + driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL); + if (driver == NULL) { + printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n"); + return -ENOMEM; + } + memset(driver, 0, sizeof(ctc_tty_driver)); + device = &driver->ctc_tty_device; + + device->magic = TTY_DRIVER_MAGIC; + device->name = ctc_ttyname; + device->major = CTC_TTY_MAJOR; + device->minor_start = 0; + device->num = CTC_TTY_MAX_DEVICES; + device->type = TTY_DRIVER_TYPE_SERIAL; + device->subtype = CTC_SERIAL_TYPE_NORMAL; + device->init_termios = tty_std_termios; + device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + device->flags = TTY_DRIVER_REAL_RAW; + device->refcount = &driver->refcount; + device->table = driver->modem_table; + device->termios = driver->modem_termios; + device->termios_locked = driver->modem_termios_locked; + device->open = ctc_tty_open; + device->close = ctc_tty_close; + device->write = ctc_tty_write; + device->put_char = NULL; + device->flush_chars = ctc_tty_flush_chars; + device->write_room = ctc_tty_write_room; + device->chars_in_buffer = ctc_tty_chars_in_buffer; + device->flush_buffer = ctc_tty_flush_buffer; + device->ioctl = ctc_tty_ioctl; + device->throttle = ctc_tty_throttle; + device->unthrottle = ctc_tty_unthrottle; + device->set_termios = ctc_tty_set_termios; + device->stop = NULL; + device->start = NULL; + device->hangup = ctc_tty_hangup; + device->driver_name = "ctc_tty"; + + if (tty_register_driver(device)) { + printk(KERN_WARNING "ctc_tty: Couldn't register serial-device\n"); + kfree(driver); + return -1; + } + for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) { + info = &driver->info[i]; + init_MUTEX(&info->write_sem); + INIT_LIST_HEAD(&info->tq.list); + info->tq.sync = 0; + info->tq.routine = (void *)(void *)ctc_tty_task; + info->tq.data = info; + info->magic = CTC_ASYNC_MAGIC; + info->line = i; + info->tty = 0; + info->x_char = 0; + info->count = 0; + info->blocked_open = 0; + info->normal_termios = device->init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + skb_queue_head_init(&info->tx_queue); + skb_queue_head_init(&info->rx_queue); + } + return 0; +} + +int +ctc_tty_register_netdev(net_device *dev) { + int ttynum; + char *err; + char *p; + + if ((!dev) || (!dev->name)) { + printk(KERN_WARNING + "ctc_tty_register_netdev called " + "with NULL dev or NULL dev-name\n"); + return -1; + } + for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++); + ttynum = simple_strtoul(p, &err, 0); + if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) || + (err && *err)) { + printk(KERN_WARNING + "ctc_tty_register_netdev called " + "with number in name '%s'\n", dev->name); + return -1; + } + if (driver->info[ttynum].netdev) { + printk(KERN_WARNING + "ctc_tty_register_netdev called " + "for already registered device '%s'\n", + dev->name); + return -1; + } + driver->info[ttynum].netdev = dev; + return 0; +} + +void +ctc_tty_unregister_netdev(net_device *dev) { + int i; + ctc_tty_info *info = NULL; + + for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) + if (driver->info[i].netdev == dev) { + info = &driver->info[i]; + break; + } + if (info) { + info->netdev = NULL; + skb_queue_purge(&info->tx_queue); + skb_queue_purge(&info->rx_queue); + } +} + +void +ctc_tty_cleanup(void) { + tty_unregister_driver(&driver->ctc_tty_device); + kfree(driver); +} diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/ctctty.h linux/drivers/s390/net/ctctty.h --- v2.4.3/linux/drivers/s390/net/ctctty.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/s390/net/ctctty.h Wed Apr 11 19:02:28 2001 @@ -0,0 +1,43 @@ +/* + * $Id: ctctty.h,v 1.2 2001/01/30 22:09:28 uweigand Exp $ + * + * CTC / ESCON network driver, tty interface. + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.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, 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 _CTCTTY_H_ +#define _CTCTTY_H_ + +#include <linux/version.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#if LINUX_VERSION_CODE < 0x020300 +typedef struct device net_device; +#else +typedef struct net_device net_device; +#endif + +extern int ctc_tty_register_netdev(net_device *dev); +extern void ctc_tty_unregister_netdev(net_device *dev); +extern void ctc_tty_netif_rx(struct sk_buff *skb); +extern int ctc_tty_init(void); +extern void ctc_tty_cleanup(void); + +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c --- v2.4.3/linux/drivers/s390/net/iucv.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/net/iucv.c Thu Apr 12 12:16:35 2001 @@ -9,7 +9,7 @@ * Alan Altmark (Alan_Altmark@us.ibm.com) */ -#include <linux/config.h> +#include <linux/module.h> #include <linux/version.h> #include <linux/spinlock.h> #include <linux/kernel.h> @@ -29,10 +29,6 @@ //#define DEBUG /* Turns Printk's on */ //#define DEBUG2 /* This prints the parameter list before and */ /* after the b2f0 call to cp */ -#ifdef CONFIG_MODULES -#define EXPORT_SYMTAB -#include <linux/module.h> -#endif #undef NULL #define NULL 0 #define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */ @@ -2021,7 +2017,6 @@ return 0; } -#ifdef CONFIG_MODULES EXPORT_SYMBOL (iucv_accept); EXPORT_SYMBOL (iucv_connect); EXPORT_SYMBOL (iucv_purge); @@ -2046,5 +2041,4 @@ EXPORT_SYMBOL (iucv_sever); EXPORT_SYMBOL (iucv_register_program); EXPORT_SYMBOL (iucv_unregister); -#endif diff -u --recursive --new-file v2.4.3/linux/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c --- v2.4.3/linux/drivers/s390/net/netiucv.c Tue Mar 6 19:44:37 2001 +++ linux/drivers/s390/net/netiucv.c Wed Apr 11 19:02:29 2001 @@ -489,7 +489,7 @@ pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid, buffer_length); - buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA); + buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA); if (buffer == NULL) { p->stats.rx_dropped++; return; diff -u --recursive --new-file v2.4.3/linux/drivers/s390/s390dyn.c linux/drivers/s390/s390dyn.c --- v2.4.3/linux/drivers/s390/s390dyn.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/s390dyn.c Wed Apr 11 19:02:28 2001 @@ -7,6 +7,7 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) */ +#include <linux/module.h> #include <linux/init.h> #include <linux/smp_lock.h> @@ -14,200 +15,149 @@ #include <asm/s390io.h> #include <asm/s390dyn.h> -static devreg_t *devreg_anchor = NULL; -static spinlock_t dyn_lock = SPIN_LOCK_UNLOCKED; +static struct list_head devreg_anchor = LIST_HEAD_INIT(devreg_anchor); +static spinlock_t dyn_lock = SPIN_LOCK_UNLOCKED; - -int s390_device_register( devreg_t *drinfo ) +static inline int s390_device_register_internal(devreg_t *drinfo) { - unsigned long flags; - int pdevflag,drflag; - - int ret = 0; - devreg_t *pdevreg = devreg_anchor; - - if ( drinfo == NULL ) - return( -EINVAL ); + struct list_head *p; - drflag = drinfo->flag; - - if ( (drflag & DEVREG_TYPE_DEVNO) == (drflag & DEVREG_TYPE_DEVCHARS) ) - return( -EINVAL ); - - spin_lock_irqsave( &dyn_lock, flags ); - - while ( (pdevreg != NULL) && (ret ==0) ) - { - if ( pdevreg == drinfo ) - { - ret = -EINVAL; - } - else - { - pdevflag = pdevreg->flag; - - /* - * we don't allow multiple drivers to register - * for the same device number - */ - if ( ( (pdevflag & DEVREG_TYPE_DEVNO) - && (pdevreg->ci.devno ) ) - && ( (drflag & DEVREG_TYPE_DEVNO ) - && (drinfo->ci.devno ) ) ) - { - ret = -EBUSY; - } - else if ( drflag == ( DEVREG_TYPE_DEVCHARS - | DEVREG_EXACT_MATCH )) - { - if ( !memcmp(&drinfo->ci.hc, - &pdevreg->ci.hc, - sizeof(devreg_hc_t))) - ret=-EBUSY; - } /* endif */ - - } /* endif */ - - pdevreg = pdevreg->next; + list_for_each(p, &devreg_anchor) { + devreg_t *pdevreg = list_entry(p, devreg_t, list); + + if (pdevreg == drinfo) + return -EINVAL; + /* + * We don't allow multiple drivers to register + * for the same device number + */ + if (pdevreg->ci.devno == drinfo->ci.devno && + (pdevreg->flag & DEVREG_TYPE_DEVNO) && + (drinfo->flag & DEVREG_TYPE_DEVNO)) + return -EBUSY; + + if (drinfo->flag == (DEVREG_TYPE_DEVCHARS | + DEVREG_EXACT_MATCH) && + !memcmp(&drinfo->ci.hc, &pdevreg->ci.hc, + sizeof(devreg_hc_t))) + return -EBUSY; + } + + /* + * no collision found, enqueue + */ + list_add (&drinfo->list, &devreg_anchor); - } /* endwhile */ + return 0; +} - /* - * only enqueue if no collision was found ... - */ - if(ret==0) - { - drinfo->next = devreg_anchor; - drinfo->prev = NULL; - - if ( devreg_anchor != NULL ) - { - devreg_anchor->prev = drinfo; - - } /* endif */ - - devreg_anchor=drinfo; +int s390_device_register( devreg_t *drinfo ) +{ + unsigned long flags; + int ret; - } /* endif */ + if (drinfo == NULL || + !(drinfo->flag & (DEVREG_TYPE_DEVNO | DEVREG_TYPE_DEVCHARS))) + return -EINVAL; + spin_lock_irqsave (&dyn_lock, flags); + ret = s390_device_register_internal(drinfo); spin_unlock_irqrestore( &dyn_lock, flags ); - return( ret); + return ret; } - -int s390_device_unregister( devreg_t *dreg ) +static inline int s390_device_unregister_internal(devreg_t *dreg) { - unsigned long flags; - - int ret = -EINVAL; - devreg_t *pdevreg = devreg_anchor; + struct list_head *p; - if ( dreg == NULL ) - return( -EINVAL ); + list_for_each(p, &devreg_anchor) { + devreg_t *pdevreg = list_entry(p, devreg_t, list); - spin_lock_irqsave( &dyn_lock, flags ); - - while ( (pdevreg != NULL ) - && ( ret != 0 ) ) - { - if ( pdevreg == dreg ) - { - devreg_t *dprev = pdevreg->prev; - devreg_t *dnext = pdevreg->next; - - if ( (dprev != NULL) && (dnext != NULL) ) - { - dnext->prev = dprev; - dprev->next = dnext; - } - if ( (dprev != NULL) && (dnext == NULL) ) - { - dprev->next = NULL; - } - if ( (dprev == NULL) && (dnext != NULL) ) - { - dnext->prev = NULL; - - } /* else */ - - ret = 0; + if (pdevreg == dreg) { + list_del (&dreg->list); + return 0; } - else - { - pdevreg = pdevreg->next; + } + return -EINVAL; +} - } /* endif */ +int s390_device_unregister(devreg_t *dreg) +{ + unsigned long flags; + int ret; - } /* endwhile */ + if (dreg == NULL) + return -EINVAL; - spin_unlock_irqrestore( &dyn_lock, flags ); + spin_lock_irqsave(&dyn_lock, flags); + ret = s390_device_unregister_internal(dreg); + spin_unlock_irqrestore(&dyn_lock, flags); - return( ret); + return ret; } +static inline devreg_t *s390_search_devreg_internal(ioinfo_t *ioinfo) +{ + struct list_head *p; + + list_for_each(p, &devreg_anchor) { + devreg_t *pdevreg = list_entry(p, devreg_t, list); + senseid_t *sid; + int flag; + + flag = pdevreg->flag; + sid = &ioinfo->senseid; + if (flag & DEVREG_TYPE_DEVNO) { + if (ioinfo->ui.flags.dval != 1 || + ioinfo->devno != pdevreg->ci.devno) + continue; + } else if ((flag & DEVREG_TYPE_DEVCHARS) && + (flag & DEVREG_EXACT_MATCH)) { + if (pdevreg->ci.hc.ctype != sid->cu_type || + pdevreg->ci.hc.cmode != sid->cu_model || + pdevreg->ci.hc.dtype != sid->dev_type || + pdevreg->ci.hc.dmode != sid->dev_model) + continue; + } else if (flag & DEVREG_TYPE_DEVCHARS) { + if (!(flag & DEVREG_NO_CU_INFO) && + pdevreg->ci.hc.ctype != sid->cu_type) + continue; + + if (!(flag & DEVREG_NO_CU_INFO) && + !(flag & DEVREG_MATCH_CU_TYPE) && + pdevreg->ci.hc.cmode != sid->cu_model) + continue; + + if (!(flag & DEVREG_NO_DEV_INFO) && + pdevreg->ci.hc.dtype != sid->dev_type) + continue; + + if (!(flag & DEVREG_NO_DEV_INFO) && + !(flag & DEVREG_MATCH_DEV_TYPE) && + pdevreg->ci.hc.dmode != sid->dev_model) + continue; + } + return pdevreg; + } + return NULL; +} devreg_t * s390_search_devreg( ioinfo_t *ioinfo ) { unsigned long flags; - devreg_hc_t match; - devreg_t *pdevreg = devreg_anchor; - - if ( ioinfo == NULL ) - return( NULL ); - - spin_lock_irqsave( &dyn_lock, flags ); + devreg_t *pdevreg; - while ( pdevreg != NULL ) - { - int flag = pdevreg->flag; - - if ( (flag & DEVREG_TYPE_DEVNO ) - && (ioinfo->ui.flags.dval == 1 ) - && (ioinfo->devno == pdevreg->ci.devno) ) - { - break; - } - else if (flag & DEVREG_TYPE_DEVCHARS ) - { - if ( flag & DEVREG_EXACT_MATCH ) - { - if ( !memcmp( &pdevreg->ci.hc, - &ioinfo->senseid.cu_type, - sizeof(devreg_hc_t))) - break; - } - else - { - memcpy( &match, &ioinfo->senseid.cu_type, - sizeof(match)); - - if( flag & DEVREG_NO_CU_INFO ) - { - match.ctype = pdevreg->ci.hc.ctype; - match.cmode = pdevreg->ci.hc.cmode; - } - if( flag & DEVREG_NO_DEV_INFO ) - { - match.dtype = pdevreg->ci.hc.dtype; - match.dmode = pdevreg->ci.hc.dmode; - } - if ( flag & DEVREG_MATCH_CU_TYPE ) - match.cmode = pdevreg->ci.hc.cmode; - if( flag & DEVREG_MATCH_DEV_TYPE) - match.dmode = pdevreg->ci.hc.dmode; - if ( !memcmp( &pdevreg->ci.hc, - &match, sizeof(match))) - break; - } /* endif */ - } /* endif */ + if (ioinfo == NULL) + return NULL; - pdevreg = pdevreg->next; - - } /* endwhile */ - - spin_unlock_irqrestore( &dyn_lock, flags ); + spin_lock_irqsave(&dyn_lock, flags); + pdevreg = s390_search_devreg_internal(ioinfo); + spin_unlock_irqrestore(&dyn_lock, flags); - return( pdevreg); + return pdevreg; } + +EXPORT_SYMBOL(s390_device_register); +EXPORT_SYMBOL(s390_device_unregister); diff -u --recursive --new-file v2.4.3/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c --- v2.4.3/linux/drivers/s390/s390io.c Tue Feb 13 14:13:44 2001 +++ linux/drivers/s390/s390io.c Wed Apr 11 19:02:29 2001 @@ -8,8 +8,16 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) * ChangeLog: 01/04/2001 Holger Smolinski (smolinsk@de.ibm.com) * Fixed lost interrupts and do_adapter_IO + * xx/xx/xxxx nnn multiple changes not reflected + * 03/12/2001 Ingo Adlung blacklist= - changed to cio_ignore= + * 03/14/2001 Ingo Adlung disable interrupts before start_IO + * in Path Group processing + * decrease retry2 on busy while + * disabling sync_isc; reset isc_cnt + * on io error during sync_isc enablement */ +#include <linux/module.h> #include <linux/config.h> #include <linux/errno.h> #include <linux/kernel_stat.h> @@ -23,7 +31,9 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/bootmem.h> - +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> @@ -34,6 +44,7 @@ #include <asm/processor.h> #include <asm/lowcore.h> #include <asm/idals.h> +#include <asm/uaccess.h> #include <asm/s390io.h> #include <asm/s390dyn.h> @@ -47,9 +58,6 @@ #undef CONFIG_DEBUG_IO #define CONFIG_DEBUG_CRW -#define REIPL_DEVID_MAGIC 0x87654321 - -struct s390_irqaction init_IRQ_action; unsigned int highest_subchannel; ioinfo_t *ioinfo_head = NULL; ioinfo_t *ioinfo_tail = NULL; @@ -58,7 +66,8 @@ }; static atomic_t sync_isc = ATOMIC_INIT(-1); - // synchronous irq processing lock +static int sync_isc_cnt = 0; // synchronous irq processing lock + static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED; // adapter interrupt lock static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc @@ -70,22 +79,7 @@ static __u64 irq_IPL_TOD; static adapter_int_handler_t adapter_handler = NULL; -/* - * Dummy controller type for unused interrupts - */ -int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;} -int enable_none(unsigned int irq) { return(-ENODEV); } -int disable_none(unsigned int irq) { return(-ENODEV); } - -struct hw_interrupt_type no_irq_type = { - "none", - do_none, - enable_none, - disable_none -}; - static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs); -static int s390_setup_irq(unsigned int irq, struct s390_irqaction * new); static void s390_process_subchannels( void); static void s390_device_recognition_all( void); static void s390_device_recognition_irq( int irq); @@ -94,8 +88,11 @@ static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid); static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid); static int s390_process_IRQ( unsigned int irq ); +static int enable_subchannel( unsigned int irq); static int disable_subchannel( unsigned int irq); +void chan_proc_init( void ); + static inline void do_adapter_IO( __u32 intparm ); int s390_DevicePathVerification( int irq, __u8 domask ); @@ -108,6 +105,305 @@ asmlinkage void do_IRQ( struct pt_regs regs ); + +/* + * "Blacklisting" of certain devices: + * Device numbers given in the commandline as blacklist=... won't be known to Linux + * These can be single devices or ranges of devices + * + * Introduced by Cornelia Huck <cohuck@de.ibm.com> + * Most of it shamelessly taken from dasd.c + */ + +typedef struct dev_blacklist_range_t { + unsigned int from; /* beginning of range */ + unsigned int to; /* end of range */ + struct dev_blacklist_range_t *next; /* next range in list */ +} dev_blacklist_range_t; + +static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */ +static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED; + +/* Handling of the blacklist ranges */ + +/* + * Function: blacklist_range_create + * Creates a range from the given parameters + */ +static inline dev_blacklist_range_t *blacklist_range_create( int from, int to) +{ + dev_blacklist_range_t *range = NULL; + range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) ); + if (range == NULL) + return NULL; + memset( range, 0, sizeof( dev_blacklist_range_t )); + range->from = from; + if (to == 0) { /* only a single device is given */ + range->to = from; + } else { + range->to = to; + } + return range; +} + +/* + * Function: blacklist_range_destroy + * Free the given range + */ + +static inline void blacklist_range_destroy( dev_blacklist_range_t *range ) +{ + kfree( range ); +} + +/* + * Function: blacklist_range_append + * Append a range to the list of blacklisted ranges anchored at dev_blacklist_range_head + */ + +static inline void blacklist_range_append( dev_blacklist_range_t *range ) +{ + dev_blacklist_range_t *temp; + long flags; + + spin_lock_irqsave( &blacklist_lock, flags ); + if (dev_blacklist_range_head == NULL) { + dev_blacklist_range_head = range; + } else { + for ( temp = dev_blacklist_range_head; + temp && temp->next; + temp = temp->next ); + temp->next = range; + } + spin_unlock_irqrestore( &blacklist_lock, flags ); +} + +/* + * Function: blacklist_range_dechain + * Remove a range from the list of blacklisted ranges + */ + +static inline void blacklist_range_dechain( dev_blacklist_range_t *range ) +{ + dev_blacklist_range_t *temp, *prev = NULL; + long flags; + + spin_lock_irqsave( &blacklist_lock, flags ); + for ( temp = dev_blacklist_range_head; temp != NULL; temp = temp->next ) { + if ( temp == range ) + break; + prev = temp; + } + if (!temp) + BUG(); + if (prev) { + prev->next = range->next; + } else { + dev_blacklist_range_head = range->next; + } + spin_unlock_irqrestore( &blacklist_lock, flags ); +} + +/* + * Function: blacklist_range_add + * Creates a range from the specified arguments and appends it to the list of + * blacklisted devices + */ + +static inline dev_blacklist_range_t *blacklist_range_add( int from, int to ) +{ + dev_blacklist_range_t *temp; + + temp = blacklist_range_create( from, to ); + if (!temp) + return NULL; + blacklist_range_append( temp ); + return temp; +} + +/* + * Function: blacklist_range_remove + * Removes a range from the blacklist chain + */ + +static inline void blacklist_range_remove( int from, int to ) +{ + dev_blacklist_range_t *temp; + + for ( temp = dev_blacklist_range_head; + (temp->from != from) && (temp->to != to); + temp = temp->next ); + blacklist_range_dechain( temp ); + blacklist_range_destroy( temp ); +} + +/* Parsing the commandline for blacklist parameters */ + +/* + * Variable to hold the blacklisted devices given by the parameter line + * blacklist=... + */ +char *blacklist[256] = {NULL, }; + +/* + * Get the blacklist=... items from the parameter line + */ + +static void blacklist_split_parm_string (char *str) +{ + char *tmp = str; + int count = 0; + do { + char *end; + int len; + end = strchr (tmp, ','); + if (end == NULL) { + len = strlen (tmp) + 1; + } else { + len = (long) end - (long) tmp + 1; + *end = '\0'; + end++; + } + blacklist[count] = alloc_bootmem (len * sizeof (char) ); + if (blacklist == NULL) { + printk (KERN_WARNING "can't store blacklist= parameter no %d\n", count + 1); + break; + } + memset (blacklist[count], 0, len * sizeof (char)); + memcpy (blacklist[count], tmp, len * sizeof (char)); + count++; + tmp = end; + } while (tmp != NULL && *tmp != '\0'); +} + +/* + * The blacklist parameters as one concatenated string + */ + +static char blacklist_parm_string[1024] __initdata = {0,}; + + +/* + * function: blacklist_strtoul + * Strip leading '0x' and interpret the values as Hex + */ +static inline int blacklist_strtoul (char *str, char **stra) +{ + char *temp = str; + int val; + if (*temp == '0') { + temp++; /* strip leading zero */ + if (*temp == 'x') + temp++; /* strip leading x */ + } + val = simple_strtoul (temp, &temp, 16); /* interpret anything as hex */ + *stra = temp; + return val; +} + +/* + * Function: blacklist_parse + * Parse the parameters given to blacklist=... + * Add the blacklisted devices to the blacklist chain + */ + +static inline void blacklist_parse( char **str ) +{ + char *temp; + int from, to; + + while (*str) { + temp = *str; + from = 0; + to = 0; + + from = blacklist_strtoul( temp, &temp ); + if (*temp == '-') { + temp++; + to = blacklist_strtoul( temp, &temp ); + } + if (!blacklist_range_add( from, to )) { + printk( KERN_WARNING "Blacklisting range from %X to %X failed!\n", from, to); + } +#ifdef CONFIG_DEBUG_IO + printk( "Blacklisted range from %X to %X\n", from, to ); +#endif + str++; + } +} + + +/* + * Initialisation of blacklist + */ + +void __init blacklist_init( void ) +{ +#ifdef CONFIG_DEBUG_IO + printk( "Reading blacklist...\n"); +#endif + blacklist_split_parm_string( blacklist_parm_string ); + blacklist_parse( blacklist ); +} + + +/* + * Get all the blacklist parameters from parameter line + */ + +void __init blacklist_setup (char *str, int *ints) +{ + int len = strlen (blacklist_parm_string); + if (len != 0) { + strcat (blacklist_parm_string, ","); + } + strcat (blacklist_parm_string, str); +} + +int __init blacklist_call_setup (char *str) +{ + int dummy; +#ifdef CONFIG_DEBUG_IO + printk( "Reading blacklist parameters...\n" ); +#endif + blacklist_setup(str,&dummy); + + blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */ + + return 1; +} + +__setup ("cio_ignore=", blacklist_call_setup); + +/* Checking if devices are blacklisted */ + +/* + * Function: is_blacklisted + * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0. + */ + +static inline int is_blacklisted( int devno ) +{ + dev_blacklist_range_t *temp; + + if (dev_blacklist_range_head == NULL) { + /* no blacklist */ + return 0; + } + + temp = dev_blacklist_range_head; + while (temp) { + if ((temp->from <= devno) && (temp->to >= devno)) { + return 1; /* Deviceno is blacklisted */ + } + temp = temp->next; + } + return 0; +} + +/* End of blacklist handling */ + + void s390_displayhex(char *str,void *ptr,s32 cnt); void s390_displayhex(char *str,void *ptr,s32 cnt) @@ -129,7 +425,7 @@ } } -static int __init cio_setup( char *parm, int *ints) +static int __init cio_setup( char *parm ) { if ( !strcmp( parm, "yes") ) { @@ -219,8 +515,8 @@ const char *devname, void *dev_id) { - int retval; - struct s390_irqaction *action; + int retval = 0; + unsigned long flags; if (irq >= __MAX_SUBCHANNELS) return -EINVAL; @@ -228,52 +524,42 @@ if ( !io_handler || !dev_id ) return -EINVAL; + if ( ioinfo[irq] == INVALID_STORAGE_AREA ) + return -ENODEV; + + /* - * during init_IRQ() processing we don't have memory - * management yet, thus need to use a statically - * allocated irqaction control block + * The following block of code has to be executed atomically */ - if ( init_IRQ_complete ) + s390irq_spin_lock_irqsave( irq, flags); + + if ( !ioinfo[irq]->ui.flags.ready ) { - action = (struct s390_irqaction *) - kmalloc( sizeof(struct s390_irqaction), - GFP_KERNEL); + ioinfo[irq]->irq_desc.handler = io_handler; + ioinfo[irq]->irq_desc.name = devname; + ioinfo[irq]->irq_desc.dev_id = dev_id; + ioinfo[irq]->ui.flags.ready = 1; + + enable_subchannel(irq); } else { - action = &init_IRQ_action; - - } /* endif */ - - if (!action) - { - return -ENOMEM; + /* + * interrupt already owned, and shared interrupts + * aren't supported on S/390. + */ + retval = -EBUSY; } /* endif */ - action->handler = io_handler; - action->flags = irqflags; - action->name = devname; - action->dev_id = dev_id; - - retval = s390_setup_irq( irq, action); - - if ( init_IRQ_complete ) - { - if ( !retval ) - { - s390_DevicePathVerification( irq, 0 ); - } - else - { - kfree(action); + s390irq_spin_unlock_irqrestore(irq,flags); - } /* endif */ - } /* endif */ if ( retval == 0 ) { + s390_DevicePathVerification( irq, 0 ); + ioinfo[irq]->ui.flags.newreq = 1; ioinfo[irq]->nopfunc = not_oper_handler; } @@ -333,10 +619,9 @@ * disable the device and reset all IRQ info if * the IRQ is actually owned by the handler ... */ - if ( ioinfo[irq]->irq_desc.action ) + if ( ioinfo[irq]->ui.flags.ready ) { - if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id ) - || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) ) + if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) { /* start deregister */ ioinfo[irq]->ui.flags.unready = 1; @@ -413,14 +698,8 @@ } while ( ret == -EBUSY ); - if ( init_IRQ_complete ) - kfree( ioinfo[irq]->irq_desc.action ); - - ioinfo[irq]->irq_desc.action = NULL; - ioinfo[irq]->ui.flags.ready = 0; - ioinfo[irq]->irq_desc.handler->enable = enable_none; - ioinfo[irq]->irq_desc.handler->disable = disable_none; - ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ + ioinfo[irq]->ui.flags.ready = 0; + ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ ioinfo[irq]->nopfunc = NULL; @@ -458,14 +737,11 @@ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return( -ENODEV); - s390irq_spin_lock_irqsave(irq, flags); + if ( !ioinfo[irq]->ui.flags.ready ) + return -ENODEV; - /* - * At this point we may actually have a pending interrupt being active - * on another CPU. So don't touch the IRQ_INPROGRESS bit.. - */ - ioinfo[irq]->irq_desc.status |= IRQ_DISABLED; - ret = ioinfo[irq]->irq_desc.handler->disable(irq); + s390irq_spin_lock_irqsave(irq, flags); + ret = disable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); synchronize_irq(); @@ -481,11 +757,11 @@ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return( -ENODEV); - s390irq_spin_lock_irqsave(irq, flags); - - ioinfo[irq]->irq_desc.status = 0; - ret = ioinfo[irq]->irq_desc.handler->enable(irq); + if ( !ioinfo[irq]->ui.flags.ready ) + return -ENODEV; + s390irq_spin_lock_irqsave(irq, flags); + ret = enable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); return(ret); @@ -717,48 +993,6 @@ } -int s390_setup_irq( unsigned int irq, struct s390_irqaction * new) -{ - unsigned long flags; - int rc = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * The following block of code has to be executed atomically - */ - s390irq_spin_lock_irqsave( irq, flags); - - if ( ioinfo[irq]->irq_desc.action == NULL ) - { - ioinfo[irq]->irq_desc.action = new; - ioinfo[irq]->irq_desc.status = 0; - ioinfo[irq]->irq_desc.handler->enable = enable_subchannel; - ioinfo[irq]->irq_desc.handler->disable = disable_subchannel; - ioinfo[irq]->irq_desc.handler->handle = handle_IRQ_event; - - ioinfo[irq]->ui.flags.ready = 1; - - ioinfo[irq]->irq_desc.handler->enable(irq); - } - else - { - /* - * interrupt already owned, and shared interrupts - * aren't supported on S/390. - */ - rc = -EBUSY; - - } /* endif */ - - s390irq_spin_unlock_irqrestore(irq,flags); - - return( rc); -} - void s390_init_IRQ( void ) { unsigned long flags; /* PSW flags */ @@ -776,7 +1010,8 @@ p_init_schib = alloc_bootmem_low( sizeof(schib_t)); p_init_irb = alloc_bootmem_low( sizeof(irb_t)); - + + /* * As we don't know about the calling environment * we assure running disabled. Before leaving the @@ -844,7 +1079,7 @@ /* * setup ORB */ - ioinfo[irq]->orb.intparm = (__u32)(__u64)&ioinfo[irq]->u_intparm; + ioinfo[irq]->orb.intparm = (__u32)(long)&ioinfo[irq]->u_intparm; ioinfo[irq]->orb.fmt = 1; ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH); @@ -864,13 +1099,10 @@ #ifdef CONFIG_ARCH_S390X /* - * for 64 bit we always support 64 bit IDAWs with 2k page - * size only - * FIXTHEM: OSA microcode currently has problems with 4k - * we would like to use 4k. + * for 64 bit we always support 64 bit IDAWs with 4k page size only */ ioinfo[irq]->orb.c64 = 1; - ioinfo[irq]->orb.i2k = 1; + ioinfo[irq]->orb.i2k = 0; #endif ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa); @@ -912,7 +1144,7 @@ * * Note : don´t clear saved irb info in case of sense ! */ - memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &((devstat_t *)ioinfo[irq]->irq_desc.dev_id)->ii.irb, '\0', sizeof( irb_t) ); } /* endif */ @@ -1086,7 +1318,7 @@ /* * initialize the device driver specific devstat irb area */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb, '\0', sizeof( irb_t) ); /* @@ -1178,8 +1410,8 @@ ioinfo[irq]->devstat.devno ); s390_displayhex( buffer, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt); + ioinfo[irq]->irq_desc.dev_id->ii.sense.data, + ioinfo[irq]->irq_desc.dev_id->rescnt); } /* endif */ } @@ -1221,7 +1453,7 @@ ret = -ENODEV; - memcpy( ioinfo[irq]->irq_desc.action->dev_id, + memcpy( ioinfo[irq]->irq_desc.dev_id, &(ioinfo[irq]->devstat), sizeof( devstat_t) ); @@ -1579,7 +1811,7 @@ /* * initialize the device driver specific devstat irb area */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb, '\0', sizeof( irb_t) ); /* @@ -1840,7 +2072,7 @@ /* * initialize the device driver specific devstat irb area */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, + memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb, '\0', sizeof( irb_t) ); /* @@ -2007,7 +2239,6 @@ unsigned int fctl; /* function control */ unsigned int stctl; /* status control */ unsigned int actl; /* activity control */ - struct s390_irqaction *action; struct pt_regs regs; /* for interface compatibility only */ int issense = 0; @@ -2015,6 +2246,7 @@ int allow4handler = 1; int chnchk = 0; devstat_t *dp; + devstat_t *udp; #if 0 int cpu = smp_processor_id(); @@ -2029,8 +2261,8 @@ } /* endif */ - action = ioinfo[irq]->irq_desc.action; - dp = &ioinfo[irq]->devstat; + dp = &ioinfo[irq]->devstat; + udp = ioinfo[irq]->irq_desc.dev_id; #ifdef CONFIG_DEBUG_IO @@ -2040,7 +2272,7 @@ * available when the device possibly becomes ready again. In * this case we perform delayed disable_subchannel() processing. */ - if ( action == NULL ) + if ( !ioinfo[irq]->ui.flags.ready ) { if ( !ioinfo[irq]->ui.flags.d_disable ) { @@ -2151,7 +2383,11 @@ } /* endif */ - if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) + if( dp->ii.irb.scsw.ectl==0) + { + issense=0; + } + else if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) && (dp->ii.irb.scsw.eswf == 0 )) { issense = 0; @@ -2262,7 +2498,7 @@ /* * take fast exit if no handler is available */ - if ( !action ) + if ( !ioinfo[irq]->ui.flags.ready ) return( ending_status ); /* @@ -2291,9 +2527,7 @@ * sensing. When finally calling the IRQ handler we must not overlay * the original device status but copy the sense data only. */ - memcpy( action->dev_id, - dp, - sizeof( devstat_t) ); + memcpy( udp, dp, sizeof( devstat_t) ); s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->sense_data ); @@ -2405,14 +2639,14 @@ "BASIC SENSE bytes avail %d\n", irq, sense_count ); #endif - ioinfo[irq]->ui.flags.w4sense = 0; - ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL; - ((devstat_t *)(action->dev_id))->scnt = sense_count; + ioinfo[irq]->ui.flags.w4sense = 0; + udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL; + udp->scnt = sense_count; if ( sense_count >= 0 ) { - memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data, - &(ioinfo[irq]->sense_data), + memcpy( udp->ii.sense.data, + ioinfo[irq]->sense_data, sense_count); } else @@ -2430,7 +2664,7 @@ } else { - memcpy( action->dev_id, dp, sdevstat ); + memcpy( udp, dp, sdevstat ); } /* endif */ @@ -2456,8 +2690,8 @@ ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; - dp->flag |= DEVSTAT_FINAL_STATUS; - action->dev_id->flag |= DEVSTAT_FINAL_STATUS; + dp->flag |= DEVSTAT_FINAL_STATUS; + udp->flag |= DEVSTAT_FINAL_STATUS; } /* endif */ @@ -2486,10 +2720,10 @@ ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; - dp->flag |= DEVSTAT_FINAL_STATUS; - action->dev_id->flag |= DEVSTAT_FINAL_STATUS; + dp->flag |= DEVSTAT_FINAL_STATUS; + udp->flag |= DEVSTAT_FINAL_STATUS; - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); // // reset intparm after final status or we will badly present unsolicited @@ -2521,7 +2755,7 @@ */ if ( ret ) { - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); } /* endif */ @@ -2539,17 +2773,17 @@ */ if ( dp->cstat & SCHN_STAT_PCI ) { - action->dev_id->flag |= DEVSTAT_PCI; - dp->cstat &= ~SCHN_STAT_PCI; + udp->flag |= DEVSTAT_PCI; + dp->cstat &= ~SCHN_STAT_PCI; } if ( actl & SCSW_ACTL_SUSPENDED ) { - action->dev_id->flag |= DEVSTAT_SUSPENDED; + udp->flag |= DEVSTAT_SUSPENDED; } /* endif */ - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); } /* endif */ @@ -2623,16 +2857,16 @@ /* * take fast exit if no handler is available */ - if ( !action ) + if ( !ioinfo[irq]->ui.flags.ready ) return( ending_status ); - memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); + memcpy( udp, &(ioinfo[irq]->devstat), sdevstat ); ioinfo[irq]->devstat.intparm = 0; if ( !ioinfo[irq]->ui.flags.s_pend ) { - action->handler( irq, action->dev_id, ®s ); + ioinfo[irq]->irq_desc.handler( irq, udp, ®s ); } /* endif */ @@ -2856,9 +3090,9 @@ if ( atomic_read( &sync_isc ) != irq ) atomic_compare_and_swap_spin( -1, irq, &sync_isc ); - ioinfo[irq]->syncnt++; + sync_isc_cnt++; - if ( ioinfo[irq]->syncnt > 255 ) /* fixme : magic number */ + if ( sync_isc_cnt > 255 ) /* fixme : magic number */ { panic("Too many recursive calls to enable_sync_isc"); @@ -2866,7 +3100,7 @@ /* * we only run the STSCH/MSCH path for the first enablement */ - else if ( ioinfo[irq]->syncnt == 1) + else if ( sync_isc_cnt == 1 ) { ioinfo[irq]->ui.flags.syncio = 1; @@ -2931,9 +3165,16 @@ } /* endif */ } /* endif */ + + if ( rc ) // can only happen if stsch/msch fails + sync_isc_cnt = 0; } else { +#ifdef CONFIG_SYNC_ISC_PARANOIA + panic( "enable_sync_isc: called with invalid %x\n", irq ); +#endif + rc = -EINVAL; } /* endif */ @@ -2960,7 +3201,14 @@ * msch() processing we may face another pending * status we have to process recursively (sync). */ - if ( (ioinfo[irq]->syncnt-1) == 0 ) + +#ifdef CONFIG_SYNC_ISC_PARANOIA + if ( atomic_read( &sync_isc ) != irq ) + panic( "disable_sync_isc: called for %x while %x locked\n", + irq, atomic_read( &sync_isc ) ); +#endif + + if ( sync_isc_cnt == 1 ) { ccode = stsch( irq, &(ioinfo[irq]->schib) ); @@ -2989,6 +3237,8 @@ retry2--; break; case 2: + retry2--; + udelay( 100); // give it time break; default: retry2 = 0; @@ -3011,20 +3261,26 @@ } while ( retry1 && ccode ); - ioinfo[irq]->syncnt = 0; ioinfo[irq]->ui.flags.syncio = 0; - + + sync_isc_cnt = 0; atomic_set( &sync_isc, -1); } else { - ioinfo[irq]->syncnt--; + sync_isc_cnt--; - } /* endif */ + } /* endif */ } else { +#ifdef CONFIG_SYNC_ISC_PARANOIA + if ( atomic_read( &sync_isc ) != -1 ) + panic( "disable_sync_isc: called with invalid %x while %x locked\n", + irq, atomic_read( &sync_isc ) ); +#endif + rc = -EINVAL; } /* endif */ @@ -3446,7 +3702,7 @@ rdc_ccw->flags = CCW_FLAG_SLI; set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf ); - memset( (devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id), + memset( ioinfo[irq]->irq_desc.dev_id, '\0', sizeof( devstat_t)); @@ -3457,7 +3713,7 @@ DOIO_WAIT_FOR_INTERRUPT | DOIO_DONT_CALL_INTHDLR ); retry--; - devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag; + devflag = ioinfo[irq]->irq_desc.dev_id->flag; clear_normalized_cda( rdc_ccw); @@ -3579,7 +3835,7 @@ } else { - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ @@ -3998,7 +4254,6 @@ void s390_device_recognition_irq( int irq ) { int ret; - unsigned long psw_flags; /* * We issue the SenseID command on I/O subchannels we think are @@ -4194,7 +4449,17 @@ if ( p_schib->pmcw.dnv ) { - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) + if ( is_blacklisted( p_schib->pmcw.dev )) { + /* + * This device must not be known to Linux. So we simply say that + * there is no device and return ENODEV. + */ +#ifdef CONFIG_DEBUG_IO + printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev ); +#endif + ret = -ENODEV; + } else { + if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { if ( !init_IRQ_complete ) { @@ -4213,8 +4478,6 @@ memcpy( &ioinfo[irq]->schib, p_init_schib, sizeof( schib_t)); - ioinfo[irq]->irq_desc.status = IRQ_DISABLED; - ioinfo[irq]->irq_desc.handler = &no_irq_type; /* * We have to insert the new ioinfo element @@ -4438,6 +4701,7 @@ ret = -ENODEV; } /* endif */ + } } else { @@ -4520,7 +4784,7 @@ { inlreq = 0; irq_ret = 0; - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ @@ -5045,6 +5309,8 @@ ccw1_t *spid_ccw; /* ccw area for SPID command */ devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; + unsigned long flags; + int irq_ret = 0; /* return code */ int retry = 5; /* retry count */ @@ -5087,13 +5353,13 @@ } else { - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ if ( irq_ret == 0 ) { - s390irq_spin_lock( irq); + s390irq_spin_lock_irqsave( irq, flags); if ( init_IRQ_complete ) { @@ -5233,7 +5499,7 @@ } /* endif */ - s390irq_spin_unlock( irq); + s390irq_spin_unlock_irqrestore( irq, flags); /* * If we installed the irq action handler we have to @@ -5301,7 +5567,7 @@ } else { - pdevstat = ioinfo[irq]->irq_desc.action->dev_id; + pdevstat = ioinfo[irq]->irq_desc.dev_id; } /* endif */ @@ -5547,7 +5813,7 @@ && ( nopfunc != NULL ) ) { - free_irq( irq,ioinfo[irq]->irq_desc.action->dev_id ); + free_irq( irq,ioinfo[irq]->irq_desc.dev_id ); nopfunc( irq,DEVSTAT_DEVICE_GONE ); } /* endif */ @@ -5659,10 +5925,170 @@ reipl ( int sch ) { int i; + s390_dev_info_t dev_info; - for ( i = 0; i < highest_subchannel; i ++ ) { - free_irq ( i, (void*)REIPL_DEVID_MAGIC ); + for ( i = 0; i <= highest_subchannel; i ++ ) + { + if ( get_dev_info_by_irq( i, &dev_info ) == 0 + && (dev_info.status & DEVSTAT_DEVICE_OWNED) ) + { + free_irq ( i, ioinfo[i]->irq_desc.dev_id ); + } } + do_reipl( 0x10000 | sch ); } +/* Display info on subchannels in /proc/subchannels. * + * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01. */ + +typedef struct { + char *data; + int len; +} tempinfo_t; + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static struct proc_dir_entry *chan_subch_entry; + +static int chan_subch_open( struct inode *inode, struct file *file) +{ + int rc = 0; + int size = 1; + int len = 0; + int i = 0; + int j = 0; + tempinfo_t *info; + + info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t)); + if (info == NULL) { + printk( KERN_WARNING "No memory available for data\n"); + return -ENOMEM; + } else { + file->private_data = ( void * ) info; + } + + size += (highest_subchannel+1) * 128; + info->data = (char *) vmalloc( size ); + + if (size && info->data == NULL) { + printk (KERN_WARNING "No memory available for data\n"); + vfree (info); + return -ENOMEM; + } + + len += sprintf( info->data+len, + "Device sch. Dev Type/Model CU in use PIM PAM POM LPUM CHPIDs\n"); + len += sprintf( info->data+len, + "--------------------------------------------------------------------------\n"); + + for ( i=0; i <= highest_subchannel; i++) { + if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) { + len += sprintf( info->data+len, + "%04X %04X ", + ioinfo[i]->schib.pmcw.dev, + i ); + if ( ioinfo[i]->senseid.dev_type != 0 ) { + len += sprintf( info->data+len, + "%04X/%02X %04X/%02X", + ioinfo[i]->senseid.dev_type, + ioinfo[i]->senseid.dev_model, + ioinfo[i]->senseid.cu_type, + ioinfo[i]->senseid.cu_model ); + } else { + len += sprintf( info->data+len, + "%04X/%02X ", + ioinfo[i]->senseid.cu_type, + ioinfo[i]->senseid.cu_model ); + } + if (ioinfo[i]->ui.flags.ready) { + len += sprintf( info->data+len, " yes " ); + } else { + len += sprintf( info->data+len, " " ); + } + len += sprintf( info->data+len, + " %02X %02X %02X %02X ", + ioinfo[i]->schib.pmcw.pim, + ioinfo[i]->schib.pmcw.pam, + ioinfo[i]->schib.pmcw.pom, + ioinfo[i]->schib.pmcw.lpum ); + for ( j=0; j < 8; j++ ) { + len += sprintf( info->data+len, + "%02X", + ioinfo[i]->schib.pmcw.chpid[j] ); + if (j==3) { + len += sprintf( info->data+len, " " ); + } + } + len += sprintf( info->data+len, "\n" ); + } + } + info->len = len; + + return rc; +} + +static int chan_subch_close( struct inode *inode, struct file *file) +{ + int rc = 0; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + + if (p_info) { + if (p_info->data) + vfree( p_info->data ); + vfree( p_info ); + } + + return rc; +} + +static ssize_t chan_subch_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset) +{ + loff_t len; + tempinfo_t *p_info = (tempinfo_t *) file->private_data; + + if ( *offset>=p_info->len) { + return 0; + } else { + len = MIN(user_len, (p_info->len - *offset)); + if (copy_to_user( user_buf, &(p_info->data[*offset]), len)) + return -EFAULT; + (* offset) += len; + return len; + } +} + +static struct file_operations chan_subch_file_ops = +{ + read:chan_subch_read, + open:chan_subch_open, + release:chan_subch_close, +}; + +void chan_proc_init( void ) +{ + chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root); + chan_subch_entry->proc_fops = &chan_subch_file_ops; +} + +__initcall(chan_proc_init); + +void chan_proc_cleanup( void ) +{ + remove_proc_entry( "subchannels", &proc_root); +} + +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); diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.4.3/linux/drivers/sbus/char/Makefile Sun Mar 25 18:14:20 2001 +++ linux/drivers/sbus/char/Makefile Thu Apr 12 12:10:25 2001 @@ -9,10 +9,11 @@ O_TARGET := sunchar.o -export-objs := su.o +export-objs := su.o bbc_i2c.o obj-y := sunkbd.o sunkbdmap.o sunmouse.o sunserial.o zs.o vfc-objs := vfc_dev.o vfc_i2c.o +bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_PCI) += su.o pcikbd.o @@ -29,6 +30,7 @@ obj-$(CONFIG_SUN_AURORA) += aurora.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o +obj-$(CONFIG_BBC_I2C) += bbc.o include $(TOPDIR)/Rules.make @@ -36,3 +38,6 @@ vfc.o: $(vfc-objs) $(LD) -r -o $@ $(vfc-objs) + +bbc.o: $(bbc-objs) + $(LD) -r -o $@ $(bbc-objs) diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/bbc_envctrl.c linux/drivers/sbus/char/bbc_envctrl.c --- v2.4.3/linux/drivers/sbus/char/bbc_envctrl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/bbc_envctrl.c Thu Apr 12 12:10:25 2001 @@ -0,0 +1,646 @@ +/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $ + * bbc_envctrl.c: UltraSPARC-III environment control driver. + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/oplib.h> +#include <asm/ebus.h> +#define __KERNEL_SYSCALLS__ +static int errno; +#include <asm/unistd.h> + +#include "bbc_i2c.h" +#include "max1617.h" + +#undef ENVCTRL_TRACE + +/* WARNING: Making changes to this driver is very dangerous. + * If you misprogram the sensor chips they can + * cut the power on you instantly. + */ + +/* Two temperature sensors exist in the SunBLADE-1000 enclosure. + * Both are implemented using max1617 i2c devices. Each max1617 + * monitors 2 temperatures, one for one of the cpu dies and the other + * for the ambient temperature. + * + * The max1617 is capable of being programmed with power-off + * temperature values, one low limit and one high limit. These + * can be controlled independantly for the cpu or ambient temperature. + * If a limit is violated, the power is simply shut off. The frequency + * with which the max1617 does temperature sampling can be controlled + * as well. + * + * Three fans exist inside the machine, all three are controlled with + * an i2c digital to analog converter. There is a fan directed at the + * two processor slots, another for the rest of the enclosure, and the + * third is for the power supply. The first two fans may be speed + * controlled by changing the voltage fed to them. The third fan may + * only be completely off or on. The third fan is meant to only be + * disabled/enabled when entering/exiting the lowest power-saving + * mode of the machine. + * + * An environmental control kernel thread periodically monitors all + * temperature sensors. Based upon the samples it will adjust the + * fan speeds to try and keep the system within a certain temperature + * range (the goal being to make the fans as quiet as possible without + * allowing the system to get too hot). + * + * If the temperature begins to rise/fall outside of the acceptable + * operating range, a periodic warning will be sent to the kernel log. + * The fans will be put on full blast to attempt to deal with this + * situation. After exceeding the acceptable operating range by a + * certain threshold, the kernel thread will shut down the system. + * Here, the thread is attempting to shut the machine down cleanly + * before the hardware based power-off event is triggered. + */ + +/* These settings are in celcius. We use these defaults only + * if we cannot interrogate the cpu-fru SEEPROM. + */ +struct temp_limits { + s8 high_pwroff, high_shutdown, high_warn; + s8 low_warn, low_shutdown, low_pwroff; +}; + +static struct temp_limits cpu_temp_limits[2] = { + { 100, 85, 80, 5, -5, -10 }, + { 100, 85, 80, 5, -5, -10 }, +}; + +static struct temp_limits amb_temp_limits[2] = { + { 65, 55, 40, 5, -5, -10 }, + { 65, 55, 40, 5, -5, -10 }, +}; + +enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; + +struct bbc_cpu_temperature { + struct bbc_cpu_temperature *next; + + struct bbc_i2c_client *client; + int index; + + /* Current readings, and history. */ + s8 curr_cpu_temp; + s8 curr_amb_temp; + s8 prev_cpu_temp; + s8 prev_amb_temp; + s8 avg_cpu_temp; + s8 avg_amb_temp; + + int sample_tick; + + enum fan_action fan_todo[2]; +#define FAN_AMBIENT 0 +#define FAN_CPU 1 +}; + +struct bbc_cpu_temperature *all_bbc_temps; + +struct bbc_fan_control { + struct bbc_fan_control *next; + + struct bbc_i2c_client *client; + int index; + + int psupply_fan_on; + int cpu_fan_speed; + int system_fan_speed; +}; + +struct bbc_fan_control *all_bbc_fans; + +#define CPU_FAN_REG 0xf0 +#define SYS_FAN_REG 0xf2 +#define PSUPPLY_FAN_REG 0xf4 + +#define FAN_SPEED_MIN 0x0c +#define FAN_SPEED_MAX 0x3f + +#define PSUPPLY_FAN_ON 0x1f +#define PSUPPLY_FAN_OFF 0x00 + +static void set_fan_speeds(struct bbc_fan_control *fp) +{ + /* Put temperatures into range so we don't mis-program + * the hardware. + */ + if (fp->cpu_fan_speed < FAN_SPEED_MIN) + fp->cpu_fan_speed = FAN_SPEED_MIN; + if (fp->cpu_fan_speed > FAN_SPEED_MAX) + fp->cpu_fan_speed = FAN_SPEED_MAX; + if (fp->system_fan_speed < FAN_SPEED_MIN) + fp->system_fan_speed = FAN_SPEED_MIN; + if (fp->system_fan_speed > FAN_SPEED_MAX) + fp->system_fan_speed = FAN_SPEED_MAX; +#ifdef ENVCTRL_TRACE + printk("fan%d: Changed fan speed to cpu(%02x) sys(%02x)\n", + fp->index, + fp->cpu_fan_speed, fp->system_fan_speed); +#endif + + bbc_i2c_writeb(fp->client, fp->cpu_fan_speed, CPU_FAN_REG); + bbc_i2c_writeb(fp->client, fp->system_fan_speed, SYS_FAN_REG); + bbc_i2c_writeb(fp->client, + (fp->psupply_fan_on ? + PSUPPLY_FAN_ON : PSUPPLY_FAN_OFF), + PSUPPLY_FAN_REG); +} + +static void get_current_temps(struct bbc_cpu_temperature *tp) +{ + tp->prev_amb_temp = tp->curr_amb_temp; + bbc_i2c_readb(tp->client, + (unsigned char *) &tp->curr_amb_temp, + MAX1617_AMB_TEMP); + tp->prev_cpu_temp = tp->curr_cpu_temp; + bbc_i2c_readb(tp->client, + (unsigned char *) &tp->curr_cpu_temp, + MAX1617_CPU_TEMP); +#ifdef ENVCTRL_TRACE + printk("temp%d: cpu(%d C) amb(%d C)\n", + tp->index, + (int) tp->curr_cpu_temp, (int) tp->curr_amb_temp); +#endif +} + + +static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) +{ + static int shutting_down = 0; + static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { "/sbin/shutdown", "-h", "now", NULL }; + char *type = "???"; + s8 val = -1; + + if (shutting_down != 0) + return; + + if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown || + tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) { + type = "ambient"; + val = tp->curr_amb_temp; + } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown || + tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) { + type = "CPU"; + val = tp->curr_cpu_temp; + } + + printk(KERN_CRIT "temp%d: Outside of safe %s " + "operating temperature, %d C.\n", + tp->index, type, val); + + printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); + + shutting_down = 1; + if (execve("/sbin/shutdown", argv, envp) < 0) + printk(KERN_CRIT "envctrl: shutdown execution failed\n"); +} + +#define WARN_INTERVAL (30 * HZ) + +static void analyze_ambient_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick) +{ + int ret = 0; + + if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) { + if (tp->curr_amb_temp >= + amb_temp_limits[tp->index].high_warn) { + printk(KERN_WARNING "temp%d: " + "Above safe ambient operating temperature, %d C.\n", + tp->index, (int) tp->curr_amb_temp); + ret = 1; + } else if (tp->curr_amb_temp < + amb_temp_limits[tp->index].low_warn) { + printk(KERN_WARNING "temp%d: " + "Below safe ambient operating temperature, %d C.\n", + tp->index, (int) tp->curr_amb_temp); + ret = 1; + } + if (ret) + *last_warn = jiffies; + } else if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_warn || + tp->curr_amb_temp < amb_temp_limits[tp->index].low_warn) + ret = 1; + + /* Now check the shutdown limits. */ + if (tp->curr_amb_temp >= amb_temp_limits[tp->index].high_shutdown || + tp->curr_amb_temp < amb_temp_limits[tp->index].low_shutdown) { + do_envctrl_shutdown(tp); + ret = 1; + } + + if (ret) { + tp->fan_todo[FAN_AMBIENT] = FAN_FULLBLAST; + } else if ((tick & (8 - 1)) == 0) { + s8 amb_goal_hi = amb_temp_limits[tp->index].high_warn - 10; + s8 amb_goal_lo; + + amb_goal_lo = amb_goal_hi - 3; + + /* We do not try to avoid 'too cold' events. Basically we + * only try to deal with over-heating and fan noise reduction. + */ + if (tp->avg_amb_temp < amb_goal_hi) { + if (tp->avg_amb_temp >= amb_goal_lo) + tp->fan_todo[FAN_AMBIENT] = FAN_SAME; + else + tp->fan_todo[FAN_AMBIENT] = FAN_SLOWER; + } else { + tp->fan_todo[FAN_AMBIENT] = FAN_FASTER; + } + } else { + tp->fan_todo[FAN_AMBIENT] = FAN_SAME; + } +} + +static void analyze_cpu_temp(struct bbc_cpu_temperature *tp, unsigned long *last_warn, int tick) +{ + int ret = 0; + + if (time_after(jiffies, (*last_warn + WARN_INTERVAL))) { + if (tp->curr_cpu_temp >= + cpu_temp_limits[tp->index].high_warn) { + printk(KERN_WARNING "temp%d: " + "Above safe CPU operating temperature, %d C.\n", + tp->index, (int) tp->curr_cpu_temp); + ret = 1; + } else if (tp->curr_cpu_temp < + cpu_temp_limits[tp->index].low_warn) { + printk(KERN_WARNING "temp%d: " + "Below safe CPU operating temperature, %d C.\n", + tp->index, (int) tp->curr_cpu_temp); + ret = 1; + } + if (ret) + *last_warn = jiffies; + } else if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_warn || + tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_warn) + ret = 1; + + /* Now check the shutdown limits. */ + if (tp->curr_cpu_temp >= cpu_temp_limits[tp->index].high_shutdown || + tp->curr_cpu_temp < cpu_temp_limits[tp->index].low_shutdown) { + do_envctrl_shutdown(tp); + ret = 1; + } + + if (ret) { + tp->fan_todo[FAN_CPU] = FAN_FULLBLAST; + } else if ((tick & (8 - 1)) == 0) { + s8 cpu_goal_hi = cpu_temp_limits[tp->index].high_warn - 10; + s8 cpu_goal_lo; + + cpu_goal_lo = cpu_goal_hi - 3; + + /* We do not try to avoid 'too cold' events. Basically we + * only try to deal with over-heating and fan noise reduction. + */ + if (tp->avg_cpu_temp < cpu_goal_hi) { + if (tp->avg_cpu_temp >= cpu_goal_lo) + tp->fan_todo[FAN_CPU] = FAN_SAME; + else + tp->fan_todo[FAN_CPU] = FAN_SLOWER; + } else { + tp->fan_todo[FAN_CPU] = FAN_FASTER; + } + } else { + tp->fan_todo[FAN_CPU] = FAN_SAME; + } +} + +static void analyze_temps(struct bbc_cpu_temperature *tp, unsigned long *last_warn) +{ + tp->avg_amb_temp = (s8)((int)((int)tp->avg_amb_temp + (int)tp->curr_amb_temp) / 2); + tp->avg_cpu_temp = (s8)((int)((int)tp->avg_cpu_temp + (int)tp->curr_cpu_temp) / 2); + + analyze_ambient_temp(tp, last_warn, tp->sample_tick); + analyze_cpu_temp(tp, last_warn, tp->sample_tick); + + tp->sample_tick++; +} + +static enum fan_action prioritize_fan_action(int which_fan) +{ + struct bbc_cpu_temperature *tp; + enum fan_action decision = FAN_STATE_MAX; + + /* Basically, prioritize what the temperature sensors + * recommend we do, and perform that action on all the + * fans. + */ + for (tp = all_bbc_temps; tp; tp = tp->next) { + if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { + decision = FAN_FULLBLAST; + break; + } + if (tp->fan_todo[which_fan] == FAN_SAME && + decision != FAN_FASTER) + decision = FAN_SAME; + else if (tp->fan_todo[which_fan] == FAN_FASTER) + decision = FAN_FASTER; + else if (decision != FAN_FASTER && + decision != FAN_SAME && + tp->fan_todo[which_fan] == FAN_SLOWER) + decision = FAN_SLOWER; + } + if (decision == FAN_STATE_MAX) + decision = FAN_SAME; + + return decision; +} + +static int maybe_new_ambient_fan_speed(struct bbc_fan_control *fp) +{ + enum fan_action decision = prioritize_fan_action(FAN_AMBIENT); + int ret; + + if (decision == FAN_SAME) + return 0; + + ret = 1; + if (decision == FAN_FULLBLAST) { + if (fp->system_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else + fp->system_fan_speed = FAN_SPEED_MAX; + } else { + if (decision == FAN_FASTER) { + if (fp->system_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else + fp->system_fan_speed += 2; + } else { + int orig_speed = fp->system_fan_speed; + + if (orig_speed <= FAN_SPEED_MIN || + orig_speed <= (fp->cpu_fan_speed - 3)) + ret = 0; + else + fp->system_fan_speed -= 1; + } + } + + return ret; +} + +static int maybe_new_cpu_fan_speed(struct bbc_fan_control *fp) +{ + enum fan_action decision = prioritize_fan_action(FAN_CPU); + int ret; + + if (decision == FAN_SAME) + return 0; + + ret = 1; + if (decision == FAN_FULLBLAST) { + if (fp->cpu_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else + fp->cpu_fan_speed = FAN_SPEED_MAX; + } else { + if (decision == FAN_FASTER) { + if (fp->cpu_fan_speed >= FAN_SPEED_MAX) + ret = 0; + else { + fp->cpu_fan_speed += 2; + if (fp->system_fan_speed < + (fp->cpu_fan_speed - 3)) + fp->system_fan_speed = + fp->cpu_fan_speed - 3; + } + } else { + if (fp->cpu_fan_speed <= FAN_SPEED_MIN) + ret = 0; + else + fp->cpu_fan_speed -= 1; + } + } + + return ret; +} + +static void maybe_new_fan_speeds(struct bbc_fan_control *fp) +{ + int new; + + new = maybe_new_ambient_fan_speed(fp); + new |= maybe_new_cpu_fan_speed(fp); + + if (new) + set_fan_speeds(fp); +} + +static void fans_full_blast(void) +{ + struct bbc_fan_control *fp; + + /* Since we will not be monitoring things anymore, put + * the fans on full blast. + */ + for (fp = all_bbc_fans; fp; fp = fp->next) { + fp->cpu_fan_speed = FAN_SPEED_MAX; + fp->system_fan_speed = FAN_SPEED_MAX; + fp->psupply_fan_on = 1; + set_fan_speeds(fp); + } +} + +#define POLL_INTERVAL (5 * HZ) +static unsigned long last_warning_jiffies; +static struct task_struct *kenvctrld_task; + +static int kenvctrld(void *__unused) +{ + daemonize(); + strcpy(current->comm, "kenvctrld"); + kenvctrld_task = current; + + printk(KERN_INFO "bbc_envctrl: kenvctrld starting...\n"); + last_warning_jiffies = jiffies - WARN_INTERVAL; + for (;;) { + struct bbc_cpu_temperature *tp; + struct bbc_fan_control *fp; + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(POLL_INTERVAL); + current->state = TASK_RUNNING; + if (signal_pending(current)) + break; + + for (tp = all_bbc_temps; tp; tp = tp->next) { + get_current_temps(tp); + analyze_temps(tp, &last_warning_jiffies); + } + for (fp = all_bbc_fans; fp; fp = fp->next) + maybe_new_fan_speeds(fp); + } + printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); + + fans_full_blast(); + + return 0; +} + +static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) +{ + struct bbc_cpu_temperature *tp = kmalloc(sizeof(*tp), GFP_KERNEL); + + if (!tp) + return; + memset(tp, 0, sizeof(*tp)); + tp->client = bbc_i2c_attach(echild); + if (!tp->client) { + kfree(tp); + return; + } + + tp->index = temp_idx; + { + struct bbc_cpu_temperature **tpp = &all_bbc_temps; + while (*tpp) + tpp = &((*tpp)->next); + tp->next = NULL; + *tpp = tp; + } + + /* Tell it to convert once every 5 seconds, clear all cfg + * bits. + */ + bbc_i2c_writeb(tp->client, 0x00, MAX1617_WR_CFG_BYTE); + bbc_i2c_writeb(tp->client, 0x02, MAX1617_WR_CVRATE_BYTE); + + /* Program the hard temperature limits into the chip. */ + bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].high_pwroff, + MAX1617_WR_AMB_HIGHLIM); + bbc_i2c_writeb(tp->client, amb_temp_limits[tp->index].low_pwroff, + MAX1617_WR_AMB_LOWLIM); + bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].high_pwroff, + MAX1617_WR_CPU_HIGHLIM); + bbc_i2c_writeb(tp->client, cpu_temp_limits[tp->index].low_pwroff, + MAX1617_WR_CPU_LOWLIM); + + get_current_temps(tp); + tp->prev_cpu_temp = tp->avg_cpu_temp = tp->curr_cpu_temp; + tp->prev_amb_temp = tp->avg_amb_temp = tp->curr_amb_temp; + + tp->fan_todo[FAN_AMBIENT] = FAN_SAME; + tp->fan_todo[FAN_CPU] = FAN_SAME; +} + +static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) +{ + struct bbc_fan_control *fp = kmalloc(sizeof(*fp), GFP_KERNEL); + + if (!fp) + return; + memset(fp, 0, sizeof(*fp)); + fp->client = bbc_i2c_attach(echild); + if (!fp->client) { + kfree(fp); + return; + } + + fp->index = fan_idx; + + { + struct bbc_fan_control **fpp = &all_bbc_fans; + while (*fpp) + fpp = &((*fpp)->next); + fp->next = NULL; + *fpp = fp; + } + + /* The i2c device controlling the fans is write-only. + * So the only way to keep track of the current power + * level fed to the fans is via software. Choose half + * power for cpu/system and 'on' fo the powersupply fan + * and set it now. + */ + fp->psupply_fan_on = 1; + fp->cpu_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2; + fp->cpu_fan_speed += FAN_SPEED_MIN; + fp->system_fan_speed = (FAN_SPEED_MAX - FAN_SPEED_MIN) / 2; + fp->system_fan_speed += FAN_SPEED_MIN; + + set_fan_speeds(fp); +} + +void bbc_envctrl_init(void) +{ + struct linux_ebus_child *echild; + int temp_index = 0; + int fan_index = 0; + int devidx = 0; + + while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { + if (!strcmp(echild->prom_name, "temperature")) + attach_one_temp(echild, temp_index++); + if (!strcmp(echild->prom_name, "fan-control")) + attach_one_fan(echild, fan_index++); + } + if (temp_index != 0 && fan_index != 0) + kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES); +} + +static void destroy_one_temp(struct bbc_cpu_temperature *tp) +{ + bbc_i2c_detach(tp->client); + kfree(tp); +} + +static void destroy_one_fan(struct bbc_fan_control *fp) +{ + bbc_i2c_detach(fp->client); + kfree(fp); +} + +void bbc_envctrl_cleanup(void) +{ + struct bbc_cpu_temperature *tp; + struct bbc_fan_control *fp; + + if (kenvctrld_task != NULL) { + force_sig(SIGKILL, kenvctrld_task); + for (;;) { + struct task_struct *p; + int found = 0; + + read_lock(&tasklist_lock); + for_each_task(p) { + if (p == kenvctrld_task) { + found = 1; + break; + } + } + read_unlock(&tasklist_lock); + if (!found) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + current->state = TASK_RUNNING; + } + kenvctrld_task = NULL; + } + + tp = all_bbc_temps; + while (tp != NULL) { + struct bbc_cpu_temperature *next = tp->next; + destroy_one_temp(tp); + tp = next; + } + all_bbc_temps = NULL; + + fp = all_bbc_fans; + while (fp != NULL) { + struct bbc_fan_control *next = fp->next; + destroy_one_fan(fp); + fp = next; + } + all_bbc_fans = NULL; +} diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/bbc_i2c.c linux/drivers/sbus/char/bbc_i2c.c --- v2.4.3/linux/drivers/sbus/char/bbc_i2c.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/bbc_i2c.c Thu Apr 12 12:10:25 2001 @@ -0,0 +1,482 @@ +/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $ + * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III + * platforms. + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <asm/oplib.h> +#include <asm/ebus.h> +#include <asm/spitfire.h> +#include <asm/bbc.h> + +#include "bbc_i2c.h" + +/* Convert this driver to use i2c bus layer someday... */ +#define I2C_PCF_PIN 0x80 +#define I2C_PCF_ESO 0x40 +#define I2C_PCF_ES1 0x20 +#define I2C_PCF_ES2 0x10 +#define I2C_PCF_ENI 0x08 +#define I2C_PCF_STA 0x04 +#define I2C_PCF_STO 0x02 +#define I2C_PCF_ACK 0x01 + +#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) +#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) + +#define I2C_PCF_INI 0x40 /* 1 if not initialized */ +#define I2C_PCF_STS 0x20 +#define I2C_PCF_BER 0x10 +#define I2C_PCF_AD0 0x08 +#define I2C_PCF_LRB 0x08 +#define I2C_PCF_AAS 0x04 +#define I2C_PCF_LAB 0x02 +#define I2C_PCF_BB 0x01 + +/* The BBC devices have two I2C controllers. The first I2C controller + * connects mainly to configuration proms (NVRAM, cpu configuration, + * dimm types, etc.). Whereas the second I2C controller connects to + * environmental control devices such as fans and temperature sensors. + * The second controller also connects to the smartcard reader, if present. + */ + +#define NUM_CHILDREN 8 +struct bbc_i2c_bus { + struct bbc_i2c_bus *next; + int index; + spinlock_t lock; + void *i2c_bussel_reg; + void *i2c_control_regs; + unsigned char own, clock; + + wait_queue_head_t wq; + volatile int waiting; + + struct linux_ebus_device *bus_edev; + struct { + struct linux_ebus_child *device; + int client_claimed; + } devs[NUM_CHILDREN]; +}; + +static struct bbc_i2c_bus *all_bbc_i2c; + +struct bbc_i2c_client { + struct bbc_i2c_bus *bp; + struct linux_ebus_child *echild; + int bus; + int address; +}; + +static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild) +{ + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (bp->devs[i].device == echild) { + if (bp->devs[i].client_claimed) + return 0; + return 1; + } + } + return 0; +} + +static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val) +{ + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (bp->devs[i].device == echild) { + bp->devs[i].client_claimed = val; + return; + } + } +} + +#define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) +#define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) + +static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + + while (bp != NULL) { + if (find_device(bp, echild) != 0) + break; + bp = bp->next; + } + + return bp; +} + +struct linux_ebus_child *bbc_i2c_getdev(int index) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + struct linux_ebus_child *echild = NULL; + int curidx = 0; + + while (bp != NULL) { + struct bbc_i2c_bus *next = bp->next; + int i; + + for (i = 0; i < NUM_CHILDREN; i++) { + if (!(echild = bp->devs[i].device)) + break; + if (curidx == index) + goto out; + echild = NULL; + curidx++; + } + bp = next; + } +out: + if (curidx == index) + return echild; + return NULL; +} + +struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) +{ + struct bbc_i2c_bus *bp = find_bus_for_device(echild); + struct bbc_i2c_client *client; + + if (!bp) + return NULL; + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return NULL; + memset(client, 0, sizeof(*client)); + client->bp = bp; + client->echild = echild; + client->bus = echild->resource[0].start; + client->address = echild->resource[1].start; + + claim_device(bp, echild); + + return client; +} + +void bbc_i2c_detach(struct bbc_i2c_client *client) +{ + struct bbc_i2c_bus *bp = client->bp; + struct linux_ebus_child *echild = client->echild; + + release_device(bp, echild); + kfree(client); +} + +static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) +{ + DECLARE_WAITQUEUE(wait, current); + int limit = 32; + int ret = 1; + + bp->waiting = 1; + add_wait_queue(&bp->wq, &wait); + while (limit-- > 0) { + u8 val; + + current->state = TASK_INTERRUPTIBLE; + *status = val = readb(bp->i2c_control_regs + 0); + if ((val & I2C_PCF_PIN) == 0) { + ret = 0; + break; + } + schedule_timeout(HZ/4); + } + remove_wait_queue(&bp->wq, &wait); + bp->waiting = 0; + current->state = TASK_RUNNING; + + return ret; +} + +int bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off) +{ + struct bbc_i2c_bus *bp = client->bp; + int address = client->address; + u8 status; + int ret = -1; + + if (bp->i2c_bussel_reg != NULL) + writeb(client->bus, bp->i2c_bussel_reg); + + writeb(address, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); + if (wait_for_pin(bp, &status)) + goto out; + + writeb(off, bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status) || + (status & I2C_PCF_LRB) != 0) + goto out; + + writeb(val, bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status)) + goto out; + + ret = 0; + +out: + writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); + return ret; +} + +int bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off) +{ + struct bbc_i2c_bus *bp = client->bp; + unsigned char address = client->address, status; + int ret = -1; + + if (bp->i2c_bussel_reg != NULL) + writeb(client->bus, bp->i2c_bussel_reg); + + writeb(address, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); + if (wait_for_pin(bp, &status)) + goto out; + + writeb(off, bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status) || + (status & I2C_PCF_LRB) != 0) + goto out; + + writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); + + address |= 0x1; /* READ */ + + writeb(address, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); + if (wait_for_pin(bp, &status)) + goto out; + + /* Set PIN back to one so the device sends the first + * byte. + */ + (void) readb(bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status)) + goto out; + + writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0); + *byte = readb(bp->i2c_control_regs + 0x1); + if (wait_for_pin(bp, &status)) + goto out; + + ret = 0; + +out: + writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); + (void) readb(bp->i2c_control_regs + 0x1); + + return ret; +} + +int bbc_i2c_write_buf(struct bbc_i2c_client *client, + char *buf, int len, int off) +{ + int ret = 0; + + while (len > 0) { + int err = bbc_i2c_writeb(client, *buf, off); + + if (err < 0) { + ret = err; + break; + } + + len--; + buf++; + off++; + } + return ret; +} + +int bbc_i2c_read_buf(struct bbc_i2c_client *client, + char *buf, int len, int off) +{ + int ret = 0; + + while (len > 0) { + int err = bbc_i2c_readb(client, buf, off); + if (err < 0) { + ret = err; + break; + } + len--; + buf++; + off++; + } + + return ret; +} + +EXPORT_SYMBOL(bbc_i2c_getdev); +EXPORT_SYMBOL(bbc_i2c_attach); +EXPORT_SYMBOL(bbc_i2c_detach); +EXPORT_SYMBOL(bbc_i2c_writeb); +EXPORT_SYMBOL(bbc_i2c_readb); +EXPORT_SYMBOL(bbc_i2c_write_buf); +EXPORT_SYMBOL(bbc_i2c_read_buf); + +static void bbc_i2c_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct bbc_i2c_bus *bp = dev_id; + + /* PIN going from set to clear is the only event which + * makes the i2c assert an interrupt. + */ + if (bp->waiting && + !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN)) + wake_up(&bp->wq); +} + +static void __init reset_one_i2c(struct bbc_i2c_bus *bp) +{ + writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); + writeb(bp->own, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); + writeb(bp->clock, bp->i2c_control_regs + 0x1); + writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); +} + +static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) +{ + struct bbc_i2c_bus *bp = kmalloc(sizeof(*bp), GFP_KERNEL); + struct linux_ebus_child *echild; + int entry; + + if (!bp) + return -ENOMEM; + memset(bp, 0, sizeof(*bp)); + + bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2); + if (!bp->i2c_control_regs) + goto fail; + + if (edev->num_addrs == 2) { + bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1); + if (!bp->i2c_bussel_reg) + goto fail; + } + + bp->waiting = 0; + init_waitqueue_head(&bp->wq); + if (request_irq(edev->irqs[0], bbc_i2c_interrupt, + SA_SHIRQ, "bbc_i2c", bp)) + goto fail; + + bp->index = index; + bp->bus_edev = edev; + + spin_lock_init(&bp->lock); + bp->next = all_bbc_i2c; + all_bbc_i2c = bp; + + entry = 0; + for (echild = edev->children; + echild && entry < 8; + echild = echild->next, entry++) { + bp->devs[entry].device = echild; + bp->devs[entry].client_claimed = 0; + } + + writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); + bp->own = readb(bp->i2c_control_regs + 0x01); + writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); + bp->clock = readb(bp->i2c_control_regs + 0x01); + + printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n", + bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock); + + reset_one_i2c(bp); + + return 0; + +fail: + if (bp->i2c_bussel_reg) + iounmap(bp->i2c_bussel_reg); + if (bp->i2c_control_regs) + iounmap(bp->i2c_control_regs); + kfree(bp); + return -EINVAL; +} + +static int __init bbc_present(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "bbc")) + return 1; + } + } + return 0; +} + +extern void bbc_envctrl_init(void); +extern void bbc_envctrl_cleanup(void); + +static int __init bbc_i2c_init(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + int index = 0; + + if (tlb_type != cheetah || !bbc_present()) + return -ENODEV; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "i2c")) { + if (!attach_one_i2c(edev, index)) + index++; + } + } + } + + if (!index) + return -ENODEV; + + bbc_envctrl_init(); + return 0; +} + +static void __exit bbc_i2c_cleanup(void) +{ + struct bbc_i2c_bus *bp = all_bbc_i2c; + + bbc_envctrl_cleanup(); + + while (bp != NULL) { + struct bbc_i2c_bus *next = bp->next; + + free_irq(bp->bus_edev->irqs[0], bp); + + if (bp->i2c_bussel_reg) + iounmap(bp->i2c_bussel_reg); + if (bp->i2c_control_regs) + iounmap(bp->i2c_control_regs); + + kfree(bp); + + bp = next; + } + all_bbc_i2c = NULL; +} + +module_init(bbc_i2c_init); +module_exit(bbc_i2c_cleanup); diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/bbc_i2c.h linux/drivers/sbus/char/bbc_i2c.h --- v2.4.3/linux/drivers/sbus/char/bbc_i2c.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/bbc_i2c.h Thu Apr 12 12:10:25 2001 @@ -0,0 +1,20 @@ +/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */ +#ifndef _BBC_I2C_H +#define _BBC_I2C_H + +#include <asm/ebus.h> + +struct bbc_i2c_client; + +/* Probing and attachment. */ +extern struct linux_ebus_child *bbc_i2c_getdev(int); +extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *); +extern void bbc_i2c_detach(struct bbc_i2c_client *); + +/* Register read/write. NOTE: Blocking! */ +extern int bbc_i2c_writeb(struct bbc_i2c_client *, unsigned char val, int off); +extern int bbc_i2c_readb(struct bbc_i2c_client *, unsigned char *byte, int off); +extern int bbc_i2c_write_buf(struct bbc_i2c_client *, char *buf, int len, int off); +extern int bbc_i2c_read_buf(struct bbc_i2c_client *, char *buf, int len, int off); + +#endif /* _BBC_I2C_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/cpwatchdog.c linux/drivers/sbus/char/cpwatchdog.c --- v2.4.3/linux/drivers/sbus/char/cpwatchdog.c Sun Mar 25 18:14:20 2001 +++ linux/drivers/sbus/char/cpwatchdog.c Thu Apr 12 12:10:25 2001 @@ -199,7 +199,9 @@ /* Forward declarations of internal methods */ +#ifdef WD_DEBUG static void wd_dumpregs(void); +#endif static void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void wd_toggleintr(struct wd_timer* pTimer, int enable); static void wd_pingtimer(struct wd_timer* pTimer); @@ -471,6 +473,7 @@ static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; +#ifdef WD_DEBUG static void wd_dumpregs(void) { /* Reading from downcounters initiates watchdog countdown-- @@ -507,6 +510,7 @@ (unsigned long)(&wd_dev.regs->pld_regs.status), readb(&wd_dev.regs->pld_regs.status)); } +#endif /* Enable or disable watchdog interrupts * Because of the CP1400 defect this should only be diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/max1617.h linux/drivers/sbus/char/max1617.h --- v2.4.3/linux/drivers/sbus/char/max1617.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/max1617.h Thu Apr 12 12:10:25 2001 @@ -0,0 +1,27 @@ +/* $Id: max1617.h,v 1.1 2001/04/02 09:59:08 davem Exp $ */ +#ifndef _MAX1617_H +#define _MAX1617_H + +#define MAX1617_AMB_TEMP 0x00 /* Ambient temp in C */ +#define MAX1617_CPU_TEMP 0x01 /* Processor die temp in C */ +#define MAX1617_STATUS 0x02 /* Chip status bits */ + +/* Read-only versions of changable registers. */ +#define MAX1617_RD_CFG_BYTE 0x03 /* Config register */ +#define MAX1617_RD_CVRATE_BYTE 0x04 /* Temp conversion rate */ +#define MAX1617_RD_AMB_HIGHLIM 0x05 /* Ambient high limit */ +#define MAX1617_RD_AMB_LOWLIM 0x06 /* Ambient low limit */ +#define MAX1617_RD_CPU_HIGHLIM 0x07 /* Processor high limit */ +#define MAX1617_RD_CPU_LOWLIM 0x08 /* Processor low limit */ + +/* Write-only versions of the same. */ +#define MAX1617_WR_CFG_BYTE 0x09 +#define MAX1617_WR_CVRATE_BYTE 0x0a +#define MAX1617_WR_AMB_HIGHLIM 0x0b +#define MAX1617_WR_AMB_LOWLIM 0x0c +#define MAX1617_WR_CPU_HIGHLIM 0x0d +#define MAX1617_WR_CPU_LOWLIM 0x0e + +#define MAX1617_ONESHOT 0x0f + +#endif /* _MAX1617_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/sbus/char/riowatchdog.c linux/drivers/sbus/char/riowatchdog.c --- v2.4.3/linux/drivers/sbus/char/riowatchdog.c Sun Mar 25 18:14:20 2001 +++ linux/drivers/sbus/char/riowatchdog.c Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: riowatchdog.c,v 1.1 2001/03/24 06:04:24 davem Exp $ +/* $Id: riowatchdog.c,v 1.2 2001/03/26 23:47:18 davem Exp $ * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -24,10 +24,9 @@ * as its' watchdog. * * When the watchdog triggers, it asserts a line to the BBC (Boot Bus - * Controller) of the machine. The BBC can be configured to treat the - * assertion of this signal in different ways. It can trigger an XIR - * (external CPU reset) to all the processors or it can trigger a true - * power-on reset which triggers the RST signal of all devices in the machine. + * Controller) of the machine. The BBC can only be configured to + * trigger a power-on reset when the signal is asserted. The BBC + * can be configured to ignore the signal entirely as well. * * The only Super I/O device register we care about is at index * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255). @@ -54,15 +53,13 @@ static spinlock_t riowd_lock = SPIN_LOCK_UNLOCKED; +static void *bbc_regs; static void *riowd_regs; #define WDTO_INDEX 0x05 static int riowd_timeout = 1; /* in minutes */ -static int riowd_xir = 1; /* watchdog generates XIR? */ MODULE_PARM(riowd_timeout,"i"); MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); -MODULE_PARM(riowd_xir,"i"); -MODULE_PARM_DESC(riowd_xir, "Watchdog generates XIR reset if non-zero"); #if 0 /* Currently unused. */ static u8 riowd_readreg(int index) @@ -96,12 +93,24 @@ static void riowd_stoptimer(void) { + u8 val; + riowd_writereg(0, WDTO_INDEX); + + val = readb(bbc_regs + BBC_WDACTION); + val &= ~BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); } static void riowd_starttimer(void) { + u8 val; + riowd_writereg(riowd_timeout, WDTO_INDEX); + + val = readb(bbc_regs + BBC_WDACTION); + val |= BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); } static int riowd_open(struct inode *inode, struct file *filp) @@ -189,7 +198,6 @@ { struct linux_ebus *ebus = NULL; struct linux_ebus_device *edev = NULL; - void *bbc_regs; u8 val; for_each_ebus(ebus) { @@ -206,14 +214,11 @@ if (!bbc_regs) return -ENODEV; + /* Turn it off. */ val = readb(bbc_regs + BBC_WDACTION); - if (riowd_xir != 0) - val &= ~BBC_WDACTION_RST; - else - val |= BBC_WDACTION_RST; + val &= ~BBC_WDACTION_RST; writeb(val, bbc_regs + BBC_WDACTION); - iounmap(bbc_regs); return 0; } @@ -249,10 +254,8 @@ goto fail; } - printk(KERN_INFO "pmc: Hardware watchdog [%i minutes, %s reset], " - "regs at %p\n", - riowd_timeout, (riowd_xir ? "XIR" : "POR"), - riowd_regs); + printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " + "regs at %p\n", riowd_timeout, riowd_regs); return 0; @@ -261,6 +264,10 @@ iounmap(riowd_regs); riowd_regs = NULL; } + if (bbc_regs) { + iounmap(bbc_regs); + bbc_regs = NULL; + } return -ENODEV; } @@ -269,6 +276,8 @@ misc_deregister(&riowd_miscdev); iounmap(riowd_regs); riowd_regs = NULL; + iounmap(bbc_regs); + bbc_regs = NULL; } module_init(riowd_init); diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.4.3/linux/drivers/scsi/53c7,8xx.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/53c7,8xx.c Wed Apr 11 19:02:36 2001 @@ -175,7 +175,7 @@ * Architecture : * This driver is built around a Linux queue of commands waiting to * be executed, and a shared Linux/NCR array of commands to start. Commands - * are transfered to the array by the run_process_issue_queue() function + * are transferred to the array by the run_process_issue_queue() function * which is called whenever a command completes. * * As commands are completed, the interrupt routine is triggered, @@ -1899,7 +1899,6 @@ hostdata->script, start); printk ("scsi%d : DSPS = 0x%x\n", host->host_no, NCR53c7x0_read32(DSPS_REG)); - restore_flags(flags); return -1; } hostdata->test_running = 0; @@ -5272,7 +5271,7 @@ * chances of this happening, and handle it if it occurs anyway. * * Simply continue with what we were doing, and control should - * be transfered to the schedule routine which will ultimately + * be transferred to the schedule routine which will ultimately * pass control onto the reselection or selection (not yet) * code. */ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h --- v2.4.3/linux/drivers/scsi/53c7,8xx.h Mon Dec 11 13:19:31 2000 +++ linux/drivers/scsi/53c7,8xx.h Wed Apr 11 19:02:37 2001 @@ -1515,11 +1515,11 @@ /* Patch field in dsa structure (assignment should be +=?) */ #define patch_dsa_32(dsa, symbol, word, value) \ { \ - (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \ + (dsa)[(hostdata->symbol - hostdata->dsa_start) / sizeof(u32) \ + (word)] = (value); \ if (hostdata->options & OPTION_DEBUG_DSA) \ printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \ - #dsa, #symbol, hostdata->##symbol, \ + #dsa, #symbol, hostdata->symbol, \ (word), (u32) le32_to_cpu(value)); \ } diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.4.3/linux/drivers/scsi/53c7xx.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/53c7xx.c Fri Apr 13 20:26:07 2001 @@ -198,7 +198,7 @@ * Architecture : * This driver is built around a Linux queue of commands waiting to * be executed, and a shared Linux/NCR array of commands to start. Commands - * are transfered to the array by the run_process_issue_queue() function + * are transferred to the array by the run_process_issue_queue() function * which is called whenever a command completes. * * As commands are completed, the interrupt routine is triggered, @@ -1077,19 +1077,18 @@ { printk("scsi%d : IRQ%d not free, detaching\n", host->host_no, host->irq); - scsi_unregister (host); - return -1; + goto err_unregister; } if ((hostdata->run_tests && hostdata->run_tests(host) == -1) || (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) { /* XXX Should disable interrupts, etc. here */ - scsi_unregister (host); - return -1; + goto err_free_irq; } else { if (host->io_port) { host->n_io_port = 128; - request_region (host->io_port, host->n_io_port, "ncr53c7xx"); + if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx")) + goto err_free_irq; } } @@ -1098,6 +1097,12 @@ hard_reset (host); } return 0; + + err_free_irq: + free_irq(host->irq, NCR53c7x0_intr); + err_unregister: + scsi_unregister(host); + return -1; } /* @@ -1206,8 +1211,11 @@ size += 256; #endif /* Size should be < 8K, so we can fit it in two pages. */ - if (size > 8192) - panic("53c7xx: hostdata > 8K"); + if (size > 8192) { + printk(KERN_ERR "53c7xx: hostdata > 8K\n"); + return -1; + } + instance = scsi_register (tpnt, 4); if (!instance) { @@ -3091,8 +3099,10 @@ #endif /* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */ - if (size > 4096) - panic ("53c7xx: allocate_cmd size > 4K"); + if (size > 4096) { + printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n"); + return NULL; + } real = get_free_page(GFP_ATOMIC); if (real == 0) return NULL; @@ -3272,7 +3282,7 @@ /* * The saved data pointer is set up so that a RESTORE POINTERS message - * will start the data transfer over at the begining. + * will start the data transfer over at the beginning. */ tmp->saved_data_pointer = virt_to_bus (hostdata->script) + @@ -4965,7 +4975,7 @@ * chances of this happening, and handle it if it occurs anyway. * * Simply continue with what we were doing, and control should - * be transfered to the schedule routine which will ultimately + * be transferred to the schedule routine which will ultimately * pass control onto the reselection or selection (not yet) * code. */ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/53c7xx.scr linux/drivers/scsi/53c7xx.scr --- v2.4.3/linux/drivers/scsi/53c7xx.scr Sat Mar 21 11:09:47 1998 +++ linux/drivers/scsi/53c7xx.scr Fri Apr 13 20:26:07 2001 @@ -1136,7 +1136,7 @@ #if (CHIP == 710) #if defined(MVME16x_INTFLY) ; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software -; interupt (SW7). We can use SCRATCH, as we are about to jump to +; interrupt (SW7). We can use SCRATCH, as we are about to jump to ; schedule, which corrupts it anyway. Will probably remove this later, ; but want to check performance effects first. diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.4.3/linux/drivers/scsi/advansys.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/advansys.c Thu Apr 12 12:16:35 2001 @@ -1,10 +1,10 @@ -/* $Id: advansys.c,v 1.69 1999/11/29 18:37:53 bobf Exp bobf $ */ -#define ASC_VERSION "3.2M" /* AdvanSys Driver Version */ +#define ASC_VERSION "3.3G" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters - * - * Copyright (c) 1995-1999 Advanced System Products, Inc. + * + * Copyright (c) 1995-2000 Advanced System Products, Inc. + * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -12,52 +12,51 @@ * code retain the above copyright notice and this comment without * modification. * + * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) + * changed its name to ConnectCom Solutions, Inc. + * * There is an AdvanSys Linux WWW page at: + * http://www.connectcom.net/downloads/software/os/linux.html * http://www.advansys.com/linux.html * - * The latest version of the AdvanSys driver is available at: + * The latest released version of the AdvanSys driver is available at: * ftp://ftp.advansys.com/pub/linux/linux.tgz + * ftp://ftp.connectcom.net/pub/linux/linux.tgz * * Please send questions, comments, bug reports to: - * linux@advansys.com + * support@connectcom.net */ /* Documentation for the AdvanSys Driver - A. Linux Kernel Testing + A. Linux Kernels Supported by this Driver B. Adapters Supported by this Driver - C. Linux v1.2.X - Directions for Adding the AdvanSys Driver - D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver - E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver - F. Source Comments - G. Driver Compile Time Options and Debugging - H. Driver LILO Option - I. Release History - J. Known Problems/Fix List - K. Credits - L. AdvanSys Contact Information - - A. Linux Kernel Testing - - This driver has been tested in the following Linux kernels: v1.2.13, - v1.3.57, v2.0.38, v2.2.13, and v2.3.28. These kernel versions are major - releases of Linux or the latest Linux kernel versions available when - this version of the driver was released. The driver should also work - in earlier versions of the Linux kernel. Beginning with v1.3.58 the - AdvanSys driver is included with all Linux kernels. Please refer to - sections C, D, and E for instructions on adding or upgrading the - AdvanSys driver. The driver is supported for x86 and alpha systems. + C. Linux source files modified by AdvanSys Driver + D. Source Comments + E. Driver Compile Time Options and Debugging + F. Driver LILO Option + G. Tests to run before releasing new driver + H. Release History + I. Known Problems/Fix List + J. Credits (Chronological Order) + K. ConnectCom (AdvanSys) Contact Information + + A. Linux Kernels Supported by this Driver + + This driver has been tested in the following Linux kernels: v2.2.18 + v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86, + alpha, and PowerPC platforms. B. Adapters Supported by this Driver - + AdvanSys (Advanced System Products, Inc.) manufactures the following RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit transfer) SCSI Host Adapters for the PCI bus. - + The CDB counts below indicate the number of SCSI CDB (Command Descriptor Block) requests that can be stored in the RISC chip cache and board LRAM. A CDB is a single SCSI command. The driver @@ -65,6 +64,9 @@ adapter detected. The number of CDBs used by the driver can be lowered in the BIOS by changing the 'Host Queue Size' adapter setting. + Laptop Products: + ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater) + Connectivity Products: ABP510/5150 - Bus-Master ISA (240 CDB) ABP5140 - Bus-Master ISA PnP (16 CDB) @@ -80,7 +82,7 @@ ABP930UA - Bus-Master PCI Ultra (16 CDB) ABP960 - Bus-Master PCI MAC/PC (16 CDB) ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) - + Single Channel Products: ABP542 - Bus-Master ISA with floppy (240 CDB) ABP742 - Bus-Master EISA (240 CDB) @@ -94,7 +96,7 @@ ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB) ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB) ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB) - + Multi-Channel Products: ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) @@ -104,37 +106,33 @@ ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel) ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.) ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB) - - C. Linux v1.2.X - Directions for Adding the AdvanSys Driver + ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB) + + C. Linux source files modified by AdvanSys Driver + + This section for historical purposes documents the changes + originally made to the Linux kernel source to add the advansys + driver. As Linux has changed some of these files have also + been modified. + + 1. linux/arch/i386/config.in: - These directions apply to v1.2.13. For versions that follow v1.2.13. - but precede v1.3.57 some of the changes for Linux v1.3.X listed - below may need to be modified or included. A patch is available - for v1.2.13 from the AdvanSys WWW and FTP sites. - - There are two source files: advansys.h and advansys.c. Copy - both of these files to the directory /usr/src/linux/drivers/scsi. - - 1. Add the following line to /usr/src/linux/arch/i386/config.in - after "comment 'SCSI low-level drivers'": - bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y - - 2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c - after "#include "hosts.h"": - + + 2. linux/drivers/scsi/hosts.c: + #ifdef CONFIG_SCSI_ADVANSYS #include "advansys.h" #endif - + and after "static Scsi_Host_Template builtin_scsi_hosts[] =": - + #ifdef CONFIG_SCSI_ADVANSYS ADVANSYS, #endif - - 3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile: - + + 3. linux/drivers/scsi/Makefile: + ifdef CONFIG_SCSI_ADVANSYS SCSI_SRCS := $(SCSI_SRCS) advansys.c SCSI_OBJS := $(SCSI_OBJS) advansys.o @@ -142,12 +140,7 @@ SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o endif - 4. (Optional) If you would like to enable the LILO command line - and /etc/lilo.conf 'advansys' option, make the following changes. - This option can be used to disable I/O port scanning or to limit - I/O port scanning to specific addresses. Refer to the 'Driver - LILO Option' section below. Add the following lines to - /usr/src/linux/init/main.c in the prototype section: + 4. linux/init/main.c: extern void advansys_setup(char *str, int *ints); @@ -157,118 +150,19 @@ { "advansys=", advansys_setup }, #endif - 5. If you have the HP 4020i CD-R driver and Linux v1.2.X you should - add a fix to the CD-ROM target driver. This fix will allow - you to mount CDs with the iso9660 file system. Linux v1.3.X - already has this fix. In the file /usr/src/linux/drivers/scsi/sr.c - and function get_sectorsize() after the line: - - if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048; - - add the following line: - - if(scsi_CDs[i].sector_size == 2340) scsi_CDs[i].sector_size = 2048; - - 6. In the directory /usr/src/linux run 'make config' to configure - the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to - make the kernel. If the AdvanSys driver is not configured, then - a loadable module can be built by running 'make modules' and - 'make modules_install'. Use 'insmod' and 'rmmod' to install - and remove advansys.o. - - D. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver - - These directions apply to v1.3.57. For versions that precede v1.3.57 - some of these changes may need to be modified or eliminated. A patch - is available for v1.3.57 from the AdvanSys WWW and FTP sites. - Beginning with v1.3.58 this driver is included with the Linux - distribution eliminating the need for making any changes. - - There are two source files: advansys.h and advansys.c. Copy - both of these files to the directory /usr/src/linux/drivers/scsi. - - 1. Add the following line to /usr/src/linux/drivers/scsi/Config.in - after "comment 'SCSI low-level drivers'": - - dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI - - 2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c - after "#include "hosts.h"": - - #ifdef CONFIG_SCSI_ADVANSYS - #include "advansys.h" - #endif - - and after "static Scsi_Host_Template builtin_scsi_hosts[] =": - - #ifdef CONFIG_SCSI_ADVANSYS - ADVANSYS, - #endif - - 3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile: - - ifeq ($(CONFIG_SCSI_ADVANSYS),y) - L_OBJS += advansys.o - else - ifeq ($(CONFIG_SCSI_ADVANSYS),m) - M_OBJS += advansys.o - endif - endif - - 4. Add the following line to /usr/src/linux/include/linux/proc_fs.h - in the enum scsi_directory_inos array: - - PROC_SCSI_ADVANSYS, - - 5. (Optional) If you would like to enable the LILO command line - and /etc/lilo.conf 'advansys' option, make the following changes. - This option can be used to disable I/O port scanning or to limit - I/O port scanning to specific addresses. Refer to the 'Driver - LILO Option' section below. Add the following lines to - /usr/src/linux/init/main.c in the prototype section: - - extern void advansys_setup(char *str, int *ints); - - and add the following lines to the bootsetups[] array. - - #ifdef CONFIG_SCSI_ADVANSYS - { "advansys=", advansys_setup }, - #endif - - 6. In the directory /usr/src/linux run 'make config' to configure - the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to - make the kernel. If the AdvanSys driver is not configured, then - a loadable module can be built by running 'make modules' and - 'make modules_install'. Use 'insmod' and 'rmmod' to install - and remove advansys.o. - - E. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver - - To upgrade the AdvanSys driver in a Linux v1.3.58 and newer - kernel, first check the version of the current driver. The - version is defined by the manifest constant ASC_VERSION at - the beginning of advansys.c. The new driver should have a - ASC_VERSION value greater than the current version. To install - the new driver rename advansys.c and advansys.h in the Linux - kernel source tree drivers/scsi directory to different names - or save them to a different directory in case you want to revert - to the old version of the driver. After the old driver is saved - copy the new advansys.c and advansys.h to drivers/scsi, rebuild - the kernel, and install the new kernel. No other changes are needed. + D. Source Comments - F. Source Comments - 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'. - + 2. This driver should be maintained in multiple files. But to make it easier to include with Linux and to follow Linux conventions, the whole driver is maintained in the source files advansys.h and advansys.c. In this file logical sections of the driver begin with a comment that contains '---'. The following are the logical sections of the driver below. - + --- Linux Version - --- Linux Include Files + --- Linux Include File --- Driver Options --- Debugging Header --- Asc Library Constants and Macros @@ -285,27 +179,27 @@ --- Tracing and Debugging Functions --- Asc Library Functions --- Adv Library Functions - + 3. The string 'XXX' is used to flag code that needs to be re-written or that contains a problem that needs to be addressed. - + 4. I have stripped comments from and reformatted the source for the Asc Library and Adv Library to reduce the size of this file. This source can be found under the following headings. The Asc Library is used to support Narrow Boards. The Adv Library is used to support Wide Boards. - + --- Asc Library Constants and Macros --- Adv Library Constants and Macros --- Asc Library Functions --- Adv Library Functions - - G. Driver Compile Time Options and Debugging - + + E. Driver Compile Time Options and Debugging + In this source file the following constants can be defined. They are defined in the source below. Both of these options are enabled by default. - + 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled) Enabling this option adds assertion logic statements to the @@ -325,11 +219,11 @@ the kernel name space. This option is very useful for debugging the driver, but it will add to the size of the driver execution image and add overhead to the execution of the driver. - + The amount of debugging output can be controlled with the global variable 'asc_dbglvl'. The higher the number the more output. By default the debug level is 0. - + If the driver is loaded at boot time and the LILO Driver Option is included in the system, the debug level can be changed by specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The @@ -343,28 +237,44 @@ If the driver is built as a loadable module this variable can be defined when the driver is loaded. The following insmod command will set the debug level to one. - + insmod advansys.o asc_dbglvl=1 - + Debugging Message Levels: 0: Errors Only 1: High-Level Tracing 2-N: Verbose Tracing - - I don't know the approved way for turning on printk()s to the - console. Here's a program I use to do this. Debug output is - logged in /var/adm/messages. - + + To enable debug output to console, please make sure that: + + a. System and kernel logging is enabled (syslogd, klogd running). + b. Kernel messages are routed to console output. Check + /etc/syslog.conf for an entry similar to this: + + kern.* /dev/console + + c. klogd is started with the appropriate -c parameter + (e.g. klogd -c 8) + + This will cause printk() messages to be be displayed on the + current console. Refer to the klogd(8) and syslogd(8) man pages + for details. + + Alternatively you can enable printk() to console with this + program. However, this is not the 'official' way to do this. + Debug output is logged in /var/log/messages. + main() { syscall(103, 7, 0, 0); } - - I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c - prevents most level 1 debug messages from being lost. + + Increasing LOG_BUF_LEN in kernel/printk.c to something like + 40960 allows more debug messages to be buffered in the kernel + and written to the console or log file. 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0) - + Enabling this option adds statistics collection and display through /proc to the driver. The information is useful for monitoring driver and device performance. It will add to the @@ -387,8 +297,8 @@ When ADVANSYS_STATS is not defined the AdvanSys /proc files only contain adapter and device configuration information. - H. Driver LILO Option - + F. Driver LILO Option + If init/main.c is modified as described in the 'Directions for Adding the AdvanSys Driver to Linux' section (B.4.) above, the driver will recognize the 'advansys' LILO command line and /etc/lilo.conf option. @@ -418,9 +328,24 @@ the 'Driver Compile Time Options and Debugging' section above for more information. - I. Release History + G. Tests to run before releasing new driver + + 1. In the supported kernels verify there are no warning or compile + errors when the kernel is built as both a driver and as a module + and with the following options: + + ADVANSYS_DEBUG - enabled and disabled + CONFIG_SMP - enabled and disabled + CONFIG_PROC_FS - enabled and disabled + + 2. Run tests on an x86, alpha, and PowerPC with at least one narrow + card and one wide card attached to a hard disk and CD-ROM drive: + fdisk, mkfs, fsck, bonnie, copy/compare test from the + CD-ROM to the hard drive. + + H. Release History - BETA-1.0 (12/23/95): + BETA-1.0 (12/23/95): First Release BETA-1.1 (12/28/95): @@ -454,7 +379,7 @@ 4. Remove reset request loop problem from the "Known Problems or Issues" section. This problem was isolated and fixed in the mid-level SCSI driver. - + 1.5 (8/8/96): 1. Add support for ABP-940U (PCI Ultra) adapter. 2. Add support for IRQ sharing by setting the SA_SHIRQ flag for @@ -677,7 +602,75 @@ 1. Really fix bug in adv_get_sglist(). 2. Incorporate v2.3.29 changes into driver. - J. Known Problems/Fix List (XXX) + 3.2N (4/1/00): + 1. Add CONFIG_ISA ifdef code. + 2. Include advansys_interrupts_enabled name change patch. + 3. For >= v2.3.28 use new SCSI error handling with new function + advansys_eh_bus_reset(). Don't include an abort function + because of base library limitations. + 4. For >= v2.3.28 use per board lock instead of io_request_lock. + 5. For >= v2.3.28 eliminate advansys_command() and + advansys_command_done(). + 6. Add some changes for PowerPC (Big Endian) support, but it isn't + working yet. + 7. Fix "nonexistent resource free" problem that occurred on a module + unload for boards with an I/O space >= 255. The 'n_io_port' field + is only one byte and can not be used to hold an ioport length more + than 255. + + 3.3A (4/4/00): + 1. Update to Adv Library 5.8. + 2. For wide cards add support for CDBs up to 16 bytes. + 3. Eliminate warnings when CONFIG_PROC_FS is not defined. + + 3.3B (5/1/00): + 1. Support for PowerPC (Big Endian) wide cards. Narrow cards + still need work. + 2. Change bitfields to shift and mask access for endian + portability. + + 3.3C (10/13/00): + 1. Update for latest 2.4 kernel. + 2. Test ABP-480 CardBus support in 2.4 kernel - works! + 3. Update to Asc Library S123. + 4. Update to Adv Library 5.12. + + 3.3D (11/22/00): + 1. Update for latest 2.4 kernel. + 2. Create patches for 2.2 and 2.4 kernels. + + 3.3E (1/9/01): + 1. Now that 2.4 is released remove ifdef code for kernel versions + less than 2.2. The driver is now only supported in kernels 2.2, + 2.4, and greater. + 2. Add code to release and acquire the io_request_lock in + the driver entrypoint functions: advansys_detect and + advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver + still holds the io_request_lock on entry to SCSI low-level drivers. + This was supposed to be removed before 2.4 was released but never + happened. When the mid-level SCSI driver is changed all references + to the io_request_lock should be removed from the driver. + 3. Simplify error handling by removing advansys_abort(), + AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are + now handled by resetting the SCSI bus and fully re-initializing + the chip. This simple method of error recovery has proven to work + most reliably after attempts at different methods. Also now only + support the "new" error handling method and remove the obsolete + error handling interface. + 4. Fix debug build errors. + + 3.3F (1/24/01): + 1. Merge with ConnectCom version from Andy Kellner which + updates Adv Library to 5.14. + 2. Make PowerPC (Big Endian) work for narrow cards and + fix problems writing EEPROM for wide cards. + 3. Remove interrupts_enabled assertion function. + + 3.3G (2/16/01): + 1. Return an error from narrow boards if passed a 16 byte + CDB. The wide board can already handle 16 byte CDBs. + + I. Known Problems/Fix List (XXX) 1. Need to add memory mapping workaround. Test the memory mapping. If it doesn't work revert to I/O port access. Can a test be done @@ -687,12 +680,12 @@ has not occurred then print a message and run in polled mode. 3. Allow bus type scanning order to be changed. 4. Need to add support for target mode commands, cf. CAM XPT. - 5 Need to add support for new Linux SCSI error handling method. - 6. Need to fix sti/cli code in Asc Library. - 7. Need to fix abort code in Adv Library. - 8. Reduce io_request_lock hold time. - K. Credits + J. Credits (Chronological Order) + + Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver + and maintained it up to 3.3F. He continues to answer questions + and help maintain the driver. Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and basis for the Linux v1.3.X changes which were included in the @@ -712,22 +705,47 @@ support in the 3.1A driver. Doug Gilbert <dgilbert@interlog.com> has made changes and - suggestions to improve the driver and done testing. + suggestions to improve the driver and done a lot of testing. Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed in 3.2K. - L. AdvanSys Contact Information - - Mail: Advanced System Products, Inc. + Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA + patch and helped with PowerPC wide and narrow board support. + + Philip Blundell <philip.blundell@pobox.com> provided an + advansys_interrupts_enabled patch. + + Dave Jones <dave@denial.force9.co.uk> reported the compiler + warnings generated when CONFIG_PROC_FS was not defined in + the 3.2M driver. + + Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian + problems) for wide cards. + + Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow + card error handling. + + Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow + board support and fixed a bug in AscGetEEPConfig(). + + Arnaldo Carvalho de Melo <acme@conectiva.com.br> made + save_flags/restore_flags changes. + + Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI + driver development for ConnectCom (Version > 3.3F). + + K. ConnectCom (AdvanSys) Contact Information + + Mail: ConnectCom Solutions, Inc. 1150 Ringwood Court San Jose, CA 95131 Operator/Sales: 1-408-383-9400 FAX: 1-408-383-9612 Tech Support: 1-408-467-2930 - Tech Support E-Mail: support@advansys.com - FTP Site: ftp.advansys.com (login: anonymous) - Web Site: http://www.advansys.com + Tech Support E-Mail: linux@connectcom.net + FTP Site: ftp.connectcom.net (login: anonymous) + Web Site: http://www.connectcom.net */ @@ -736,78 +754,62 @@ * --- Linux Version */ -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) - #ifndef LINUX_VERSION_CODE #include <linux/version.h> #endif /* LINUX_VERSION_CODE */ +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0)) + +/* Driver supported only in version 2.2 and version >= 2.4. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ + (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ + LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels." +#endif /* - * --- Linux Include Files + * --- Linux Include Files */ #include <linux/config.h> -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #ifdef MODULE #include <linux/module.h> #endif /* MODULE */ -#endif /* version >= v1.3.0 */ + +#if defined(CONFIG_X86) && !defined(CONFIG_ISA) +#define CONFIG_ISA +#endif /* CONFIG_X86 && !CONFIG_ISA */ + #include <linux/string.h> #include <linux/sched.h> #include <linux/kernel.h> -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -#include <linux/head.h> -#endif /* verions < v2.1.0 */ #include <linux/types.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/mm.h> -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #include <linux/proc_fs.h> -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23) #include <linux/init.h> -#endif /* version >= v2.1.23 */ #include <asm/io.h> #include <asm/system.h> #include <asm/dma.h> -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#include "../block/blk.h" -#else /* version >= v1.3.0 */ #include <linux/blk.h> #include <linux/stat.h> -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,18) +#if ASC_LINUX_KERNEL24 #include <linux/spinlock.h> -#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95) +#elif ASC_LINUX_KERNEL22 #include <asm/spinlock.h> -#endif /* version >= 2.1.95 */ +#endif #include "scsi.h" #include "hosts.h" #include "sd.h" #include "advansys.h" -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,93) #ifdef CONFIG_PCI #include <linux/pci.h> #endif /* CONFIG_PCI */ -#else /* version < v2.1.93 */ -/* - * For earlier than v2.1.93 the driver has its own PCI configuration. - * If PCI is not needed in a kernel before v2.1.93 this define can be - * turned-off to make the driver object smaller. - */ -#define ASC_CONFIG_PCI -#endif /* version < v2.1.93 */ - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -#define cpu_to_le16(word) (word) -#define le16_to_cpu(word) (word) -#define cpu_to_le32(dword) (dword) -#define le32_to_cpu(dword) (dword) -#endif /* version < v2.1.0 */ /* @@ -817,19 +819,12 @@ /* Enable driver assertions. */ #define ADVANSYS_ASSERT +/* Enable driver /proc statistics. */ +#define ADVANSYS_STATS + /* Enable driver tracing. */ /* #define ADVANSYS_DEBUG */ -/* - * Because of no /proc to display them, statistics are disabled - * for versions prior to v1.3.0. - */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#undef ADVANSYS_STATS /* Disable statistics */ -#else /* version >= v1.3.0 */ -#define ADVANSYS_STATS /* Enable statistics. */ -#endif /* version >= v1.3.0 */ - /* * --- Debugging Header @@ -848,7 +843,7 @@ #define ASC_LIB_VERSION_MAJOR 1 #define ASC_LIB_VERSION_MINOR 24 -#define ASC_LIB_SERIAL_NUMBER 121 +#define ASC_LIB_SERIAL_NUMBER 123 /* * Portable Data Types @@ -858,7 +853,7 @@ * types must be used. In Linux the char, short, and int types * are all consistent at 8, 16, and 32 bits respectively. Pointers * and long types are 64 bits on Alpha and UltraSPARC. - */ + */ #define ASC_PADDR __u32 /* Physical/Bus address data type. */ #define ASC_VADDR __u32 /* Virtual address data type. */ #define ASC_DCNT __u32 /* Unsigned Data count type. */ @@ -907,7 +902,7 @@ #define ASC_PCI_VENDORID 0x10CD #define ASC_PCI_DEVICEID_1200A 0x1100 #define ASC_PCI_DEVICEID_1200B 0x1200 -#define ASC_PCI_DEVICEID_ULTRA 0x1300 +#define ASC_PCI_DEVICEID_ULTRA 0x1300 #define ASC_PCI_REVISION_3150 0x02 #define ASC_PCI_REVISION_3050 0x03 @@ -924,13 +919,13 @@ #define CC_VERY_LONG_SG_LIST 0 #define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) -#define PortAddr unsigned short /* port address size */ -#define inp(port) inb(port) -#define inpw(port) inw(port) -#define inpl(port) inl(port) -#define outp(port, byte) outb((byte), (port)) -#define outpw(port, word) outw((word), (port)) -#define outpl(port, dword) outl((dword), (port)) +#define PortAddr unsigned short /* port address size */ +#define inp(port) inb(port) +#define outp(port, byte) outb((byte), (port)) + +#define inpw(port) inw(port) +#define outpw(port, word) outw((word), (port)) + #define ASC_MAX_SG_QUEUE 7 #define ASC_MAX_SG_LIST 255 @@ -977,12 +972,7 @@ #define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) #define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) -#ifndef inpw_noswap -#define inpw_noswap(port) inpw(port) -#endif -#ifndef outpw_noswap -#define outpw_noswap(port, data) outpw(port, data) -#endif + #define ASC_SCSI_ID_BITS 3 #define ASC_SCSI_TIX_TYPE uchar #define ASC_ALL_DEVICE_BIT_SET 0xFF @@ -1024,6 +1014,8 @@ #define SCSICMD_ReadHeader 0x44 #define SCSICMD_ModeSelect10 0x55 #define SCSICMD_ModeSense10 0x5A + +/* Inquiry Data Peripheral Device Types */ #define SCSI_TYPE_DASD 0x00 #define SCSI_TYPE_SASD 0x01 #define SCSI_TYPE_PRN 0x02 @@ -1035,10 +1027,20 @@ #define SCSI_TYPE_MED_CHG 0x08 #define SCSI_TYPE_COMM 0x09 #define SCSI_TYPE_UNKNOWN 0x1F -#define SCSI_TYPE_NO_DVC 0xFF -#define INQ_CLOCKING_ST_ONLY 0x0 -#define INQ_CLOCKING_DT_ONLY 0x1 -#define INQ_CLOCKING_ST_AND_DT 0x3 + +#define ADV_INQ_CLOCKING_ST_ONLY 0x0 +#define ADV_INQ_CLOCKING_DT_ONLY 0x1 +#define ADV_INQ_CLOCKING_ST_AND_DT 0x3 + +/* + * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data) + * and CmdDt (Command Support Data) field bit definitions. + */ +#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3 +#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2 +#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1 +#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0 + #define ASC_SCSIDIR_NOCHK 0x00 #define ASC_SCSIDIR_T2H 0x08 #define ASC_SCSIDIR_H2T 0x10 @@ -1102,77 +1104,49 @@ #define M2_QTAG_MSG_ORDERED 0x22 #define M2_IGNORE_WIDE_RESIDUE 0x23 -typedef struct { - uchar peri_dvc_type:5; - uchar peri_qualifier:3; -} ASC_SCSI_INQ0; - -typedef struct { - uchar dvc_type_modifier:7; - uchar rmb:1; -} ASC_SCSI_INQ1; - -typedef struct { - uchar ansi_apr_ver:3; - uchar ecma_ver:3; - uchar iso_ver:2; -} ASC_SCSI_INQ2; - -typedef struct { - uchar rsp_data_fmt:4; - uchar res:2; - uchar TemIOP:1; - uchar aenc:1; -} ASC_SCSI_INQ3; - -typedef struct { - uchar StfRe:1; - uchar CmdQue:1; - uchar Reserved:1; - uchar Linked:1; - uchar Sync:1; - uchar WBus16:1; - uchar WBus32:1; - uchar RelAdr:1; -} ASC_SCSI_INQ7; +/* + * Inquiry data structure and bitfield macros + * + * Only quantities of more than 1 bit are shifted, since the others are + * just tested for true or false. C bitfields aren't portable between big + * and little-endian platforms so they are not used. + */ + +#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f) +#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5) +#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f) +#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80) +#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07) +#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3) +#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6) +#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f) +#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40) +#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80) +#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01) +#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02) +#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08) +#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10) +#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20) +#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40) +#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80) +#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01) +#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02) +#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2) typedef struct { - ASC_SCSI_INQ0 byte0; - ASC_SCSI_INQ1 byte1; - ASC_SCSI_INQ2 byte2; - ASC_SCSI_INQ3 byte3; + uchar periph; + uchar devtype; + uchar ver; + uchar byte3; uchar add_len; uchar res1; uchar res2; - ASC_SCSI_INQ7 byte7; + uchar flags; uchar vendor_id[8]; uchar product_id[16]; uchar product_rev_level[4]; } ASC_SCSI_INQUIRY; -typedef struct asc_req_sense { - uchar err_code:7; - uchar info_valid:1; - uchar segment_no; - uchar sense_key:4; - uchar reserved_bit:1; - uchar sense_ILI:1; - uchar sense_EOM:1; - uchar file_mark:1; - uchar info1[4]; - uchar add_sense_len; - uchar cmd_sp_info[4]; - uchar asc; - uchar ascq; - uchar fruc; - uchar sks_byte0:7; - uchar sks_valid:1; - uchar sks_bytes[2]; - uchar notused[2]; - uchar ex_sense_code; - uchar info2[4]; -} ASC_REQ_SENSE; - #define ASC_SG_LIST_PER_Q 7 #define QS_FREE 0x00 #define QS_READY 0x01 @@ -1286,7 +1260,7 @@ #define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN) #define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6)) -typedef struct asc_scisq_1 { +typedef struct asc_scsiq_1 { uchar status; uchar q_no; uchar cntl; @@ -1300,7 +1274,7 @@ uchar extra_bytes; } ASC_SCSIQ_1; -typedef struct asc_scisq_2 { +typedef struct asc_scsiq_2 { ASC_VADDR srb_ptr; uchar target_ix; uchar flag; @@ -1378,8 +1352,8 @@ typedef struct asc_scsi_req_q { ASC_SCSIQ_1 r1; ASC_SCSIQ_2 r2; - uchar *cdbptr; - ASC_SG_HEAD *sg_head; + uchar *cdbptr; + ASC_SG_HEAD *sg_head; uchar *sense_ptr; ASC_SCSIQ_3 r3; uchar cdb[ASC_MAX_CDB_LEN]; @@ -1461,6 +1435,10 @@ #define ASCQ_ERR_SEND_SCSI_Q 0x22 #define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23 #define ASCQ_ERR_RESET_SDTR 0x24 + +/* + * Warning code values are set in ASC_DVC_VAR 'warn_code'. + */ #define ASC_WARN_NO_ERROR 0x0000 #define ASC_WARN_IO_PORT_ROTATE 0x0001 #define ASC_WARN_EEPROM_CHKSUM 0x0002 @@ -1470,6 +1448,10 @@ #define ASC_WARN_EEPROM_RECOVER 0x0020 #define ASC_WARN_CFG_MSW_RECOVER 0x0040 #define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 + +/* + * Error code values are set in ASC_DVC_VAR 'err_code'. + */ #define ASC_IERR_WRITE_EEPROM 0x0001 #define ASC_IERR_MCODE_CHKSUM 0x0002 #define ASC_IERR_SET_PC_ADDR 0x0004 @@ -1484,6 +1466,7 @@ #define ASC_IERR_SCAM 0x0800 #define ASC_IERR_SET_SDTR 0x1000 #define ASC_IERR_RW_LRAM 0x8000 + #define ASC_DEF_IRQ_NO 10 #define ASC_MAX_IRQ_NO 15 #define ASC_MIN_IRQ_NO 10 @@ -1578,8 +1561,8 @@ ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled; ASC_SCSI_BIT_ID_TYPE disc_enable; ASC_SCSI_BIT_ID_TYPE sdtr_enable; - uchar chip_scsi_id:4; - uchar isa_dma_speed:4; + uchar chip_scsi_id; + uchar isa_dma_speed; uchar isa_dma_channel; uchar chip_version; ushort pci_device_id; @@ -1703,6 +1686,20 @@ #define ASC_MAX_INIT_BUSY_RETRY 8 #define ASC_EEP_ISA_PNP_WSIZE 16 +/* + * These macros keep the chip SCSI id and ISA DMA speed + * bitfields in board order. C bitfields aren't portable + * between big and little-endian platforms so they are + * not used. + */ + +#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f) +#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4) +#define ASC_EEP_SET_CHIP_ID(cfg, sid) \ + ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID)) +#define ASC_EEP_SET_DMA_SPD(cfg, spd) \ + ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4) + typedef struct asceep_config { ushort cfg_lsw; ushort cfg_msw; @@ -1715,8 +1712,8 @@ uchar bios_scan; uchar power_up_wait; uchar no_scam; - uchar chip_scsi_id:4; - uchar isa_dma_speed:4; + uchar id_speed; /* low order 4 bits is chip scsi id */ + /* high order 4 bits is isa dma speed */ uchar dos_int13_table[ASC_MAX_TID + 1]; uchar adapter_info[6]; ushort cntl; @@ -1962,8 +1959,6 @@ #define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr) #define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA) #define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data) -#define AscGetChipLramDataNoSwap(port) (ushort)inpw_noswap((port)+IOP_RAM_DATA) -#define AscSetChipLramDataNoSwap(port, data) outpw_noswap((port)+IOP_RAM_DATA, data) #define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC) #define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data) #define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS) @@ -2021,21 +2016,24 @@ STATIC void AscEnableInterrupt(PortAddr); STATIC void AscSetBank(PortAddr, uchar); STATIC int AscResetChipAndScsiBus(ASC_DVC_VAR *); +#ifdef CONFIG_ISA STATIC ushort AscGetIsaDmaChannel(PortAddr); STATIC ushort AscSetIsaDmaChannel(PortAddr, ushort); STATIC uchar AscSetIsaDmaSpeed(PortAddr, uchar); STATIC uchar AscGetIsaDmaSpeed(PortAddr); +#endif /* CONFIG_ISA */ STATIC uchar AscReadLramByte(PortAddr, ushort); STATIC ushort AscReadLramWord(PortAddr, ushort); +#if CC_VERY_LONG_SG_LIST STATIC ASC_DCNT AscReadLramDWord(PortAddr, ushort); +#endif /* CC_VERY_LONG_SG_LIST */ STATIC void AscWriteLramWord(PortAddr, ushort, ushort); -STATIC void AscWriteLramDWord(PortAddr, ushort, ASC_DCNT); STATIC void AscWriteLramByte(PortAddr, ushort, uchar); STATIC ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int); STATIC void AscMemWordSetLram(PortAddr, ushort, ushort, int); -STATIC void AscMemWordCopyToLram(PortAddr, ushort, ushort *, int); -STATIC void AscMemDWordCopyToLram(PortAddr, ushort, ASC_DCNT *, int); -STATIC void AscMemWordCopyFromLram(PortAddr, ushort, ushort *, int); +STATIC void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int); +STATIC void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int); +STATIC void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int); STATIC ushort AscInitAscDvcVar(ASC_DVC_VAR *); STATIC ushort AscInitFromEEP(ASC_DVC_VAR *); STATIC ushort AscInitFromAscDvcVar(ASC_DVC_VAR *); @@ -2047,21 +2045,8 @@ STATIC uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar); STATIC uchar AscAllocFreeQueue(PortAddr, uchar); STATIC uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar); -STATIC int AscRiscHaltedAbortSRB(ASC_DVC_VAR *, ASC_DCNT); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int AscRiscHaltedAbortTIX(ASC_DVC_VAR *, uchar); -#endif /* version >= v1.3.89 */ STATIC int AscHostReqRiscHalt(PortAddr); STATIC int AscStopQueueExe(PortAddr); -STATIC int AscStartQueueExe(PortAddr); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int AscCleanUpDiscQueue(PortAddr); -#endif /* version >= v1.3.89 */ -STATIC int AscCleanUpBusyQueue(PortAddr); -STATIC int AscWaitTixISRDone(ASC_DVC_VAR *, uchar); -STATIC int AscWaitISRDone(ASC_DVC_VAR *); -STATIC ASC_PADDR AscGetOnePhyAddr(ASC_DVC_VAR *, uchar *, - ASC_DCNT); STATIC int AscSendScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q * scsiq, uchar n_q_required); @@ -2072,48 +2057,43 @@ STATIC int AscSetChipSynRegAtID(PortAddr, uchar, uchar); STATIC int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar); STATIC ushort AscInitLram(ASC_DVC_VAR *); -STATIC int AscReInitLram(ASC_DVC_VAR *); STATIC ushort AscInitQLinkVar(ASC_DVC_VAR *); STATIC int AscSetLibErrorCode(ASC_DVC_VAR *, ushort); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int _AscWaitQDone(PortAddr, ASC_SCSI_Q *); -#endif /* version >= v1.3.89 */ STATIC int AscIsrChipHalted(ASC_DVC_VAR *); STATIC uchar _AscCopyLramScsiDoneQ(PortAddr, ushort, ASC_QDONE_INFO *, ASC_DCNT); STATIC int AscIsrQDone(ASC_DVC_VAR *); STATIC int AscCompareString(uchar *, uchar *, int); +#ifdef CONFIG_ISA STATIC ushort AscGetEisaChipCfg(PortAddr); STATIC ASC_DCNT AscGetEisaProductID(PortAddr); STATIC PortAddr AscSearchIOPortAddrEISA(PortAddr); +STATIC PortAddr AscSearchIOPortAddr11(PortAddr); +STATIC PortAddr AscSearchIOPortAddr(PortAddr, ushort); +STATIC void AscSetISAPNPWaitForKey(void); +#endif /* CONFIG_ISA */ STATIC uchar AscGetChipScsiCtrl(PortAddr); STATIC uchar AscSetChipScsiID(PortAddr, uchar); STATIC uchar AscGetChipVersion(PortAddr, ushort); STATIC ushort AscGetChipBusType(PortAddr); -STATIC ASC_DCNT AscLoadMicroCode(PortAddr, ushort, ushort *, ushort); +STATIC ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort); STATIC int AscFindSignature(PortAddr); -STATIC PortAddr AscSearchIOPortAddr11(PortAddr); STATIC void AscToggleIRQAct(PortAddr); -STATIC void AscSetISAPNPWaitForKey(void); STATIC uchar AscGetChipIRQ(PortAddr, ushort); STATIC uchar AscSetChipIRQ(PortAddr, uchar, ushort); STATIC ushort AscGetChipBiosAddress(PortAddr, ushort); -STATIC int DvcEnterCritical(void); -STATIC void DvcLeaveCritical(int); -STATIC void DvcInPortWords(PortAddr, ushort *, int); -STATIC void DvcOutPortWords(PortAddr, ushort *, int); -STATIC void DvcOutPortDWords(PortAddr, ASC_DCNT *, int); +STATIC inline ulong DvcEnterCritical(void); +STATIC inline void DvcLeaveCritical(ulong); +#ifdef CONFIG_PCI STATIC uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort); STATIC void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar); +#endif /* CONFIG_PCI */ STATIC ushort AscGetChipBiosAddress(PortAddr, ushort); STATIC void DvcSleepMilliSecond(ASC_DCNT); STATIC void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT); -STATIC ASC_DCNT DvcGetSGList(ASC_DVC_VAR *, uchar *, - ASC_DCNT, ASC_SG_HEAD *); -STATIC void DvcPutScsiQ(PortAddr, ushort, ushort *, int); -STATIC void DvcGetQinfo(PortAddr, ushort, ushort *, int); -STATIC PortAddr AscSearchIOPortAddr(PortAddr, ushort); +STATIC void DvcPutScsiQ(PortAddr, ushort, uchar *, int); +STATIC void DvcGetQinfo(PortAddr, ushort, uchar *, int); STATIC ushort AscInitGetConfig(ASC_DVC_VAR *); STATIC ushort AscInitSetConfig(ASC_DVC_VAR *); STATIC ushort AscInitAsc1000Driver(ASC_DVC_VAR *); @@ -2127,12 +2107,9 @@ STATIC uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar); STATIC int AscSgListToQueue(int); -STATIC int AscAbortSRB(ASC_DVC_VAR *, ASC_VADDR); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int AscResetDevice(ASC_DVC_VAR *, uchar); -#endif /* version >= v1.3.89 */ -STATIC int AscResetSB(ASC_DVC_VAR *); +#ifdef CONFIG_ISA STATIC void AscEnableIsaDma(uchar); +#endif /* CONFIG_ISA */ STATIC ASC_DCNT AscGetMaxDmaCount(ushort); @@ -2141,7 +2118,7 @@ */ #define ADV_LIB_VERSION_MAJOR 5 -#define ADV_LIB_VERSION_MINOR 5 +#define ADV_LIB_VERSION_MINOR 14 /* d_os_dep.h */ #define ADV_OS_LINUX @@ -2158,7 +2135,7 @@ * types must be used. In Linux the char, short, and int types * are all consistent at 8, 16, and 32 bits respectively. Pointers * and long types are 64 bits on Alpha and UltraSPARC. - */ + */ #define ADV_PADDR __u32 /* Physical address data type. */ #define ADV_VADDR __u32 /* Virtual address data type. */ #define ADV_DCNT __u32 /* Unsigned Data count type. */ @@ -2175,11 +2152,7 @@ #define ADV_VADDR_TO_U32 virt_to_bus #define ADV_U32_TO_VADDR bus_to_virt -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#define AdvPortAddr unsigned short /* I/O Port address size */ -#else /* version >= v1,3,0 */ #define AdvPortAddr ulong /* Virtual memory address size */ -#endif /* version >= v1,3,0 */ /* * Define Adv Library required memory access macros. @@ -2188,16 +2161,15 @@ #define ADV_MEM_READW(addr) readw(addr) #define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr) #define ADV_MEM_WRITEW(addr, word) writew(word, addr) +#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr) + +#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) /* - * The I/O memory mapping function names changed in 2.1.X. + * For wide boards a CDB length maximum of 16 bytes + * is supported. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -#define ioremap vremap -#define iounmap vfree -#endif /* version < v2.1.0 */ - -#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) +#define ADV_MAX_CDB_LEN 16 /* * Define total number of simultaneous maximum element scatter-gather @@ -2207,7 +2179,7 @@ * elements. Allow each command to have at least one ADV_SG_BLOCK structure. * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK * structures or 255 scatter-gather elements. - * + * */ #define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG @@ -2225,10 +2197,10 @@ #define ADV_SG_TOTAL_MEM_SIZE \ (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK) -#define ASC_PAGE_SIZE PAGE_SIZE +#define ADV_PAGE_SIZE PAGE_SIZE #define ADV_NUM_PAGE_CROSSING \ - ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE) + ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) /* a_condor.h */ #define ADV_PCI_VENDOR_ID 0x10CD @@ -2236,12 +2208,12 @@ #define ADV_PCI_DEVID_38C0800_REV1 0x2500 #define ADV_PCI_DEVID_38C1600_REV1 0x2700 -#define ASC_EEP_DVC_CFG_BEGIN (0x00) -#define ASC_EEP_DVC_CFG_END (0x15) -#define ASC_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ -#define ASC_EEP_MAX_WORD_ADDR (0x1E) +#define ADV_EEP_DVC_CFG_BEGIN (0x00) +#define ADV_EEP_DVC_CFG_END (0x15) +#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ +#define ADV_EEP_MAX_WORD_ADDR (0x1E) -#define ASC_EEP_DELAY_MS 100 +#define ADV_EEP_DELAY_MS 100 #define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ #define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ @@ -2252,6 +2224,18 @@ */ #define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ #define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */ +/* + * ASC38C1600 Bit 11 + * + * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify + * INT A in the PCI Configuration Space Int Pin field. If it is 1, then + * Function 0 will specify INT B. + * + * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify + * INT B in the PCI Configuration Space Int Pin field. If it is 1, then + * Function 1 will specify INT A. + */ +#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */ typedef struct adveep_3550_config { @@ -2262,20 +2246,20 @@ /* bit 14 set - BIOS Enable */ /* bit 15 set - Big Endian Mode */ ushort cfg_msw; /* 01 unused */ - ushort disc_enable; /* 02 disconnect enable */ + ushort disc_enable; /* 02 disconnect enable */ ushort wdtr_able; /* 03 Wide DTR able */ ushort sdtr_able; /* 04 Synchronous DTR able */ - ushort start_motor; /* 05 send start up motor */ + ushort start_motor; /* 05 send start up motor */ ushort tagqng_able; /* 06 tag queuing able */ - ushort bios_scan; /* 07 BIOS device control */ - ushort scam_tolerant; /* 08 no scam */ - + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + uchar adapter_scsi_id; /* 09 Host Adapter ID */ uchar bios_boot_delay; /* power up wait */ - + uchar scsi_reset_delay; /* 10 reset delay */ uchar bios_id_lun; /* first boot device scsi id & lun */ - /* high nibble is lun */ + /* high nibble is lun */ /* low nibble is scsi id */ uchar termination; /* 11 0 - automatic */ @@ -2284,33 +2268,33 @@ /* 3 - low on / high on */ /* There is no low on / high off */ - uchar reserved1; /* reserved byte (not used) */ + uchar reserved1; /* reserved byte (not used) */ ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 set: BIOS don't act as initiator. */ - /* bit 1 set: BIOS > 1 GB support */ - /* bit 2 set: BIOS > 2 Disk Support */ - /* bit 3 set: BIOS don't support removables */ - /* bit 4 set: BIOS support bootable CD */ - /* bit 5 set: */ - /* bit 6 set: BIOS support multiple LUNs */ - /* bit 7 set: BIOS display of message */ - /* bit 8 set: */ - /* bit 9 set: Reset SCSI bus during init. */ - /* bit 10 set: */ - /* bit 11 set: No verbose initialization. */ - /* bit 12 set: SCSI parity enabled */ - /* bit 13 set: */ - /* bit 14 set: */ - /* bit 15 set: */ - ushort ultra_able; /* 13 ULTRA speed able */ + /* bit 0 BIOS don't act as initiator. */ + /* bit 1 BIOS > 1 GB support */ + /* bit 2 BIOS > 2 Disk Support */ + /* bit 3 BIOS don't support removables */ + /* bit 4 BIOS support bootable CD */ + /* bit 5 BIOS scan enabled */ + /* bit 6 BIOS support multiple LUNs */ + /* bit 7 BIOS display of message */ + /* bit 8 SCAM disabled */ + /* bit 9 Reset SCSI bus during init. */ + /* bit 10 */ + /* bit 11 No verbose initialization. */ + /* bit 12 SCSI parity enabled */ + /* bit 13 */ + /* bit 14 */ + /* bit 15 */ + ushort ultra_able; /* 13 ULTRA speed able */ ushort reserved2; /* 14 reserved */ uchar max_host_qng; /* 15 maximum host queuing */ uchar max_dvc_qng; /* maximum per device queuing */ ushort dvc_cntl; /* 16 control bit for driver */ ushort bug_fix; /* 17 control bit for bug fix */ - ushort serial_number_word1; /* 18 Board serial number word 1 */ - ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ ushort serial_number_word3; /* 20 Board serial number word 3 */ ushort check_sum; /* 21 EEP check sum */ uchar oem_name[16]; /* 22 OEM name */ @@ -2319,9 +2303,9 @@ ushort adv_err_addr; /* 32 last uc error address */ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ - ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ ushort num_of_err; /* 36 number of error */ -} ADVEEP_3550_CONFIG; +} ADVEEP_3550_CONFIG; typedef struct adveep_38C0800_config { @@ -2361,22 +2345,22 @@ /* There is no low on / high off */ ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 set: BIOS don't act as initiator. */ - /* bit 1 set: BIOS > 1 GB support */ - /* bit 2 set: BIOS > 2 Disk Support */ - /* bit 3 set: BIOS don't support removables */ - /* bit 4 set: BIOS support bootable CD */ - /* bit 5 set: BIOS scan enabled */ - /* bit 6 set: BIOS support multiple LUNs */ - /* bit 7 set: BIOS display of message */ - /* bit 8 set: */ - /* bit 9 set: Reset SCSI bus during init. */ - /* bit 10 set: */ - /* bit 11 set: No verbose initialization. */ - /* bit 12 set: SCSI parity enabled */ - /* bit 13 set: */ - /* bit 14 set: */ - /* bit 15 set: */ + /* bit 0 BIOS don't act as initiator. */ + /* bit 1 BIOS > 1 GB support */ + /* bit 2 BIOS > 2 Disk Support */ + /* bit 3 BIOS don't support removables */ + /* bit 4 BIOS support bootable CD */ + /* bit 5 BIOS scan enabled */ + /* bit 6 BIOS support multiple LUNs */ + /* bit 7 BIOS display of message */ + /* bit 8 SCAM disabled */ + /* bit 9 Reset SCSI bus during init. */ + /* bit 10 */ + /* bit 11 No verbose initialization. */ + /* bit 12 SCSI parity enabled */ + /* bit 13 */ + /* bit 14 */ + /* bit 15 */ ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ uchar max_host_qng; /* 15 maximum host queueing */ @@ -2424,6 +2408,109 @@ ushort reserved63; /* 63 reserved */ } ADVEEP_38C0800_CONFIG; +typedef struct adveep_38C1600_config +{ + /* Word Offset, Description */ + + ushort cfg_lsw; /* 00 power up initialization */ + /* bit 11 set - Func. 0 INTB, Func. 1 INTA */ + /* clear - Func. 0 INTA, Func. 1 INTB */ + /* bit 13 set - Load CIS */ + /* bit 14 set - BIOS Enable */ + /* bit 15 set - Big Endian Mode */ + ushort cfg_msw; /* 01 unused */ + ushort disc_enable; /* 02 disconnect enable */ + ushort wdtr_able; /* 03 Wide DTR able */ + ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */ + ushort start_motor; /* 05 send start up motor */ + ushort tagqng_able; /* 06 tag queuing able */ + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + + uchar adapter_scsi_id; /* 09 Host Adapter ID */ + uchar bios_boot_delay; /* power up wait */ + + uchar scsi_reset_delay; /* 10 reset delay */ + uchar bios_id_lun; /* first boot device scsi id & lun */ + /* high nibble is lun */ + /* low nibble is scsi id */ + + uchar termination_se; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + uchar termination_lvd; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + ushort bios_ctrl; /* 12 BIOS control bits */ + /* bit 0 BIOS don't act as initiator. */ + /* bit 1 BIOS > 1 GB support */ + /* bit 2 BIOS > 2 Disk Support */ + /* bit 3 BIOS don't support removables */ + /* bit 4 BIOS support bootable CD */ + /* bit 5 BIOS scan enabled */ + /* bit 6 BIOS support multiple LUNs */ + /* bit 7 BIOS display of message */ + /* bit 8 SCAM disabled */ + /* bit 9 Reset SCSI bus during init. */ + /* bit 10 Basic Integrity Checking disabled */ + /* bit 11 No verbose initialization. */ + /* bit 12 SCSI parity enabled */ + /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */ + /* bit 14 */ + /* bit 15 */ + ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ + ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ + uchar max_host_qng; /* 15 maximum host queueing */ + uchar max_dvc_qng; /* maximum per device queuing */ + ushort dvc_cntl; /* 16 control bit for driver */ + ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word3; /* 20 Board serial number word 3 */ + ushort check_sum; /* 21 EEP check sum */ + uchar oem_name[16]; /* 22 OEM name */ + ushort dvc_err_code; /* 30 last device driver error code */ + ushort adv_err_code; /* 31 last uc and Adv Lib error code */ + ushort adv_err_addr; /* 32 last uc error address */ + ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ + ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort reserved36; /* 36 reserved */ + ushort reserved37; /* 37 reserved */ + ushort reserved38; /* 38 reserved */ + ushort reserved39; /* 39 reserved */ + ushort reserved40; /* 40 reserved */ + ushort reserved41; /* 41 reserved */ + ushort reserved42; /* 42 reserved */ + ushort reserved43; /* 43 reserved */ + ushort reserved44; /* 44 reserved */ + ushort reserved45; /* 45 reserved */ + ushort reserved46; /* 46 reserved */ + ushort reserved47; /* 47 reserved */ + ushort reserved48; /* 48 reserved */ + ushort reserved49; /* 49 reserved */ + ushort reserved50; /* 50 reserved */ + ushort reserved51; /* 51 reserved */ + ushort reserved52; /* 52 reserved */ + ushort reserved53; /* 53 reserved */ + ushort reserved54; /* 54 reserved */ + ushort reserved55; /* 55 reserved */ + ushort cisptr_lsw; /* 56 CIS PTR LSW */ + ushort cisprt_msw; /* 57 CIS PTR MSW */ + ushort subsysvid; /* 58 SubSystem Vendor ID */ + ushort subsysid; /* 59 SubSystem ID */ + ushort reserved60; /* 60 reserved */ + ushort reserved61; /* 61 reserved */ + ushort reserved62; /* 62 reserved */ + ushort reserved63; /* 63 reserved */ +} ADVEEP_38C1600_CONFIG; + /* * EEPROM Commands */ @@ -2445,6 +2532,7 @@ #define BIOS_CTRL_RESET_SCSI_BUS 0x0200 #define BIOS_CTRL_INIT_VERBOSE 0x0800 #define BIOS_CTRL_SCSI_PARITY 0x1000 +#define BIOS_CTRL_AIPP_DIS 0x2000 #define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */ #define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */ @@ -2452,7 +2540,14 @@ #define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */ #define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */ -#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ +/* + * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is + * a special 16K Adv Library and Microcode version. After the issue is + * resolved, should restore 32K support. + * + * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory * + */ +#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ #define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */ #define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */ @@ -2653,8 +2748,8 @@ #define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */ #define FILTER_SEL 0x0C00 /* Filter Period Selection */ #define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */ -#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ -#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ +#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ +#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ #define ACTIVE_DBL 0x0200 /* Disable Active Negation */ #define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */ #define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */ @@ -2666,6 +2761,14 @@ /* * Addendum for ASC-38C0800 Chip + * + * The ASC-38C1600 Chip uses the same definitions except that the + * bus mode override bits [12:10] have been moved to byte register + * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in + * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV) + * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only. + * Also each ASC-38C1600 function or channel uses only cable bits [5:4] + * and [1:0]. Bits [14], [7:6], [3:2] are unused. */ #define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */ #define HVD_LVD_SE 0x1C00 /* Device Detect Bits */ @@ -2745,6 +2848,33 @@ #define PRE_TEST_VALUE 0x05 #define NORMAL_VALUE 0x00 +/* + * ASC38C1600 Definitions + * + * IOPB_PCI_INT_CFG Bit Field Definitions + */ + +#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */ + +/* + * Bit 1 can be set to change the interrupt for the Function to operate in + * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in + * Open Drain mode. Both functions of the ASC38C1600 must be set to the same + * mode, otherwise the operating mode is undefined. + */ +#define TOTEMPOLE 0x02 + +/* + * Bit 0 can be used to change the Int Pin for the Function. The value is + * 0 by default for both Functions with Function 0 using INT A and Function + * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set, + * INT A is used. + * + * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin + * value specified in the PCI Configuration Space. + */ +#define INTAB 0x01 + /* a_advlib.h */ /* @@ -2759,7 +2889,7 @@ /* - * ASC_DVC_VAR 'warn_code' values + * ADV_DVC_VAR 'warn_code' values */ #define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */ #define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ @@ -2770,11 +2900,8 @@ #define ADV_MAX_TID 15 /* max. target identifier */ #define ADV_MAX_LUN 7 /* max. logical unit number */ - /* - * AscInitGetConfig() and AscInitAsc1000Driver() Definitions - * - * Error code values are set in ASC_DVC_VAR 'err_code'. + * Error code values are set in ADV_DVC_VAR 'err_code'. */ #define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */ #define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ @@ -2829,6 +2956,7 @@ #define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */ #define ASC_MC_ICQ 0x0160 #define ASC_MC_IRQ 0x0164 +#define ASC_MC_PPR_ABLE 0x017A /* * BIOS LRAM variable absolute offsets. @@ -2845,6 +2973,7 @@ * and handled by the microcode. */ #define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */ +#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */ /* * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format @@ -2876,6 +3005,10 @@ #define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */ #define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */ +/* + * All fields here are accessed by the board microcode and need to be + * little-endian. + */ typedef struct adv_carr_t { ADV_VADDR carr_va; /* Carrier Virtual Address */ @@ -2896,12 +3029,11 @@ #define ASC_NEXT_VPA_MASK 0xFFFFFFF0 #define ASC_RQ_DONE 0x00000001 +#define ASC_RQ_GOOD 0x00000002 #define ASC_CQ_STOPPER 0x00000000 #define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK) -#define ADV_PAGE_SIZE 4096 /* Assume 4KB page size. */ - #define ADV_CARRIER_NUM_PAGE_CROSSING \ (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \ (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE) @@ -2929,7 +3061,7 @@ * This structure can be discarded after initialization. Don't add * fields here needed after initialization. * - * Field naming convention: + * Field naming convention: * * *_enable indicates the field enables or disables a feature. The * value of the field is never reset. @@ -2949,7 +3081,7 @@ ushort serial1; /* EEPROM serial number word 1 */ ushort serial2; /* EEPROM serial number word 2 */ ushort serial3; /* EEPROM serial number word 3 */ -} ADV_DVC_CFG; +} ADV_DVC_CFG; struct adv_dvc_var; struct adv_scsi_req_q; @@ -2965,7 +3097,7 @@ * * One structure is required per host adapter. * - * Field naming convention: + * Field naming convention: * * *_able indicates both whether a feature should be enabled or disabled * and whether a device isi capable of the feature. At initialization @@ -2986,6 +3118,7 @@ ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */ ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */ ushort tagqng_able; /* try tagged queuing with a device */ + ushort ppr_able; /* PPR message capable per TID bitmask. */ uchar max_dvc_qng; /* maximum number of tagged commands per device */ ushort start_motor; /* start motor command allowed */ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ @@ -3007,13 +3140,13 @@ * driver may discard the buffer after initialization is done. */ ADV_DVC_CFG *cfg; /* temporary configuration structure */ -} ADV_DVC_VAR; +} ADV_DVC_VAR; #define NO_OF_SG_PER_BLOCK 15 typedef struct asc_sg_block { - uchar reserved1; - uchar reserved2; + uchar reserved1; + uchar reserved2; uchar reserved3; uchar sg_cnt; /* Valid entries in block. */ ADV_PADDR sg_ptr; /* Pointer to next sg block. */ @@ -3030,6 +3163,9 @@ * The microcode makes assumptions about the size and ordering of fields * in this structure. Do not change the structure definition here without * coordinating the change with the microcode. + * + * All fields accessed by microcode must be maintained in little_endian + * order. */ typedef struct adv_scsi_req_q { uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */ @@ -3042,16 +3178,16 @@ ADV_PADDR carr_pa; uchar mflag; uchar sense_len; - uchar cdb_len; /* SCSI CDB length. */ + uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */ uchar scsi_cntl; uchar done_status; /* Completion status. */ uchar scsi_status; /* SCSI status byte. */ uchar host_status; /* Ucode host status. */ uchar sg_working_ix; - uchar cdb[12]; /* SCSI command block. */ + uchar cdb[12]; /* SCSI CDB bytes 0-11. */ ADV_PADDR sg_real_addr; /* SG list physical address. */ ADV_PADDR scsiq_rptr; - ADV_DCNT sg_working_data_cnt; + uchar cdb16[4]; /* SCSI CDB bytes 12-15. */ ADV_VADDR scsiq_ptr; ADV_VADDR carr_va; /* @@ -3062,6 +3198,7 @@ ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ char *vdata_addr; /* Data buffer virtual address. */ uchar a_flag; + uchar pad[2]; /* Pad out to a word boundary. */ } ADV_SCSI_REQ_Q; /* @@ -3097,14 +3234,16 @@ #define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */ #define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */ #define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */ +#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */ + #define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */ /* * Device drivers must define the following functions. */ -STATIC int DvcEnterCritical(void); -STATIC void DvcLeaveCritical(int); +STATIC inline ulong DvcEnterCritical(void); +STATIC inline void DvcLeaveCritical(ulong); STATIC void DvcSleepMilliSecond(ADV_DCNT); STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort); STATIC void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar); @@ -3120,6 +3259,7 @@ STATIC int AdvInitGetConfig(ADV_DVC_VAR *); STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *); STATIC int AdvInitAsc38C0800Driver(ADV_DVC_VAR *); +STATIC int AdvInitAsc38C1600Driver(ADV_DVC_VAR *); STATIC int AdvResetChipAndSB(ADV_DVC_VAR *); STATIC int AdvResetSB(ADV_DVC_VAR *asc_dvc); @@ -3130,10 +3270,13 @@ STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); STATIC int AdvInitFrom3550EEP(ADV_DVC_VAR *); STATIC int AdvInitFrom38C0800EEP(ADV_DVC_VAR *); +STATIC int AdvInitFrom38C1600EEP(ADV_DVC_VAR *); STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); STATIC void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *); STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); STATIC void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *); +STATIC ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *); +STATIC void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *); STATIC void AdvWaitEEPCmd(AdvPortAddr); STATIC ushort AdvReadEEPWord(AdvPortAddr, int); @@ -3143,71 +3286,9 @@ #define AscPCICmdRegBits_BusMastering 0x0007 #define AscPCICmdRegBits_ParErrRespCtrl 0x0040 -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - /* Read byte from a register. */ #define AdvReadByteRegister(iop_base, reg_off) \ - (inp((iop_base) + (reg_off))) - -/* Write byte to a register. */ -#define AdvWriteByteRegister(iop_base, reg_off, byte) \ - (outp((iop_base) + (reg_off), (byte))) - -/* Read word (2 bytes) from a register. */ -#define AdvReadWordRegister(iop_base, reg_off) \ - (le16_to_cpu(inpw((iop_base) + (reg_off)))) - -/* Write word (2 bytes) to a register. */ -#define AdvWriteWordRegister(iop_base, reg_off, word) \ - (outpw((iop_base) + (reg_off), cpu_to_le16(word))) - -/* Read byte from LRAM. */ -#define AdvReadByteLram(iop_base, addr, byte) \ -do { \ - outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (byte) = inp((iop_base) + IOPB_RAM_DATA); \ -} while (0) - -/* Write byte to LRAM. */ -#define AdvWriteByteLram(iop_base, addr, byte) \ - (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ - outp((iop_base) + IOPB_RAM_DATA, (byte))) - -/* Read word (2 bytes) from LRAM. */ -#define AdvReadWordLram(iop_base, addr, word) \ -do { \ - outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (word) = le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA)); \ -} while (0) - -/* Write word (2 bytes) to LRAM. */ -#define AdvWriteWordLram(iop_base, addr, word) \ - (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ - outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) - -/* Write double word (4 bytes) to LRAM */ -/* Because of unspecified C language ordering don't use auto-increment. */ -#define AdvWriteDWordLram(iop_base, addr, dword) \ - ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ - outpw((iop_base) + IOPW_RAM_DATA, \ - cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \ - (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ - outpw((iop_base) + IOPW_RAM_DATA, \ - cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF))))) - -/* Read word (2 bytes) from LRAM assuming that the address is already set. */ -#define AdvReadWordAutoIncLram(iop_base) \ - (le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA))) - -/* Write word (2 bytes) to LRAM assuming that the address is already set. */ -#define AdvWriteWordAutoIncLram(iop_base, word) \ - (outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) - -#else /* version >= v1,3,0 */ - -/* Read byte from a register. */ -#define AdvReadByteRegister(iop_base, reg_off) \ - (ADV_MEM_READB((iop_base) + (reg_off))) + (ADV_MEM_READB((iop_base) + (reg_off))) /* Write byte to a register. */ #define AdvWriteByteRegister(iop_base, reg_off, byte) \ @@ -3215,11 +3296,15 @@ /* Read word (2 bytes) from a register. */ #define AdvReadWordRegister(iop_base, reg_off) \ - le16_to_cpu(ADV_MEM_READW((iop_base) + (reg_off))) + (ADV_MEM_READW((iop_base) + (reg_off))) /* Write word (2 bytes) to a register. */ #define AdvWriteWordRegister(iop_base, reg_off, word) \ - (ADV_MEM_WRITEW((iop_base) + (reg_off), cpu_to_le16(word))) + (ADV_MEM_WRITEW((iop_base) + (reg_off), (word))) + +/* Write dword (4 bytes) to a register. */ +#define AdvWriteDWordRegister(iop_base, reg_off, dword) \ + (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword))) /* Read byte from LRAM. */ #define AdvReadByteLram(iop_base, addr, byte) \ @@ -3237,17 +3322,17 @@ #define AdvReadWordLram(iop_base, addr, word) \ do { \ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (word) = le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \ + (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \ } while (0) /* Write word (2 bytes) to LRAM. */ #define AdvWriteWordLram(iop_base, addr, word) \ (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) -/* Write double word (4 bytes) to LRAM */ +/* Write little-endian double word (4 bytes) to LRAM */ /* Because of unspecified C language ordering don't use auto-increment. */ -#define AdvWriteDWordLram(iop_base, addr, dword) \ +#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \ ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \ @@ -3257,13 +3342,12 @@ /* Read word (2 bytes) from LRAM assuming that the address is already set. */ #define AdvReadWordAutoIncLram(iop_base) \ - le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) + (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) /* Write word (2 bytes) to LRAM assuming that the address is already set. */ #define AdvWriteWordAutoIncLram(iop_base, word) \ - (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word))) + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) -#endif /* version >= v1,3,0 */ /* * Define macro to check for Condor signature. @@ -3288,7 +3372,7 @@ /* * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must * match the ASC_SCSI_REQ_Q 'srb_ptr' field. - * + * * If the request has not yet been sent to the device it will simply be * aborted from RISC memory. If the request is disconnected it will be * aborted on reselection by sending an Abort Message to the target ID. @@ -3376,6 +3460,7 @@ */ extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; +extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; /* * DvcGetPhyAddr() flag arguments @@ -3388,8 +3473,9 @@ #define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */ /* Return the address that is aligned at the next doubleword >= to 'addr'. */ -#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3) +#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7) #define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF) +#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F) /* * Total contiguous memory needed for driver SG blocks. @@ -3399,50 +3485,76 @@ * single request. */ -#ifndef ADV_MAX_SG_LIST -Forced Error: Driver must define ADV_MAX_SG_LIST. -#endif /* ADV_MAX_SG_LIST */ - #define ADV_SG_LIST_MAX_BYTE_SIZE \ (sizeof(ADV_SG_BLOCK) * \ ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)) +/* + * Inquiry data structure and bitfield macros + * + * Using bitfields to access the subchar data isn't portable across + * endianness, so instead mask and shift. Only quantities of more + * than 1 bit are shifted, since the others are just tested for true + * or false. + */ + +#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f) +#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5) +#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f) +#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80) +#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07) +#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3) +#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6) +#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f) +#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40) +#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80) +#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01) +#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02) +#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08) +#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10) +#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20) +#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40) +#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80) +#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01) +#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02) +#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2) + typedef struct { - uchar peri_dvc_type : 5; /* peripheral device type */ - uchar peri_qualifier : 3; /* peripheral qualifier */ - uchar dvc_type_modifier : 7; /* device type modifier (for SCSI I) */ - uchar rmb : 1; /* RMB - removable medium bit */ - uchar ansi_apr_ver : 3; /* ANSI approved version */ - uchar ecma_ver : 3; /* ECMA version */ - uchar iso_ver : 2; /* ISO version */ - uchar rsp_data_fmt : 4; /* response data format */ + uchar periph; /* peripheral device type [0:4] */ + /* peripheral qualifier [5:7] */ + uchar devtype; /* device type modifier (for SCSI I) [0:6] */ + /* RMB - removable medium bit [7] */ + uchar ver; /* ANSI approved version [0:2] */ + /* ECMA version [3:5] */ + /* ISO version [6:7] */ + uchar byte3; /* response data format [0:3] */ /* 0 SCSI 1 */ /* 1 CCS */ /* 2 SCSI-2 */ /* 3-F reserved */ - uchar res1 : 2; /* reserved */ - uchar TemIOP : 1; /* terminate I/O process bit (see 5.6.22) */ - uchar aenc : 1; /* asynch. event notification (processor) */ + /* reserved [4:5] */ + /* terminate I/O process bit (see 5.6.22) [6] */ + /* asynch. event notification (processor) [7] */ uchar add_len; /* additional length */ + uchar res1; /* reserved */ uchar res2; /* reserved */ - uchar res3; /* reserved */ - uchar StfRe : 1; /* soft reset implemented */ - uchar CmdQue : 1; /* command queuing */ - uchar res4 : 1; /* reserved */ - uchar Linked : 1; /* linked command for this logical unit */ - uchar Sync : 1; /* synchronous data transfer */ - uchar WBus16 : 1; /* wide bus 16 bit data transfer */ - uchar WBus32 : 1; /* wide bus 32 bit data transfer */ - uchar RelAdr : 1; /* relative addressing mode */ + uchar flags; /* soft reset implemented [0] */ + /* command queuing [1] */ + /* reserved [2] */ + /* linked command for this logical unit [3] */ + /* synchronous data transfer [4] */ + /* wide bus 16 bit data transfer [5] */ + /* wide bus 32 bit data transfer [6] */ + /* relative addressing mode [7] */ uchar vendor_id[8]; /* vendor identification */ uchar product_id[16]; /* product identification */ uchar product_rev_level[4]; /* product revision level */ uchar vendor_specific[20]; /* vendor specific */ - uchar IUS : 1; /* information unit supported */ - uchar QAS : 1; /* quick arbitrate supported */ - uchar Clocking : 2; /* clocking field */ - uchar res5 : 4; /* reserved */ - uchar res6; /* reserved */ + uchar info; /* information unit supported [0] */ + /* quick arbitrate supported [1] */ + /* clocking field [2:3] */ + /* reserved [4:7] */ + uchar res3; /* reserved */ } ADV_SCSI_INQUIRY; /* 58 bytes */ @@ -3459,7 +3571,6 @@ /* asc_board_t flags */ #define ASC_HOST_IN_RESET 0x01 -#define ASC_HOST_IN_ABORT 0x02 #define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */ #define ASC_SELECT_QUEUE_DEPTHS 0x08 @@ -3473,22 +3584,17 @@ * and data after loading, define macros for this purpose. These macros * are not used when the driver is built as a module, cf. linux/init.h. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23) -#define ASC_INITFUNC(type, func) type func -#define ASC_INITDATA -#define ASC_INIT -#else /* version >= v2.1.23 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16) -#define ASC_INITFUNC(type, func) __initfunc(type func) -#else /* version >= v2.3.16 */ +#if ASC_LINUX_KERNEL24 #define ASC_INITFUNC(type, func) type __init func -#endif /* version >= v2.3.16 */ +#elif ASC_LINUX_KERNEL22 +#define ASC_INITFUNC(type, func) __initfunc(type func) +#endif #define ASC_INITDATA __initdata #define ASC_INIT __init -#endif /* version >= v2.1.23 */ #define ASC_INFO_SIZE 128 /* advansys_info() line size */ +#ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] related definitions */ #define ASC_PRTBUF_SIZE 2048 #define ASC_PRTLINE_SIZE 160 @@ -3504,6 +3610,37 @@ } #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* CONFIG_PROC_FS */ + +/* + * XXX - Release and acquire the io_request_lock. These macros are needed + * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock' + * on entry to SCSI low-level drivers. + * + * These definitions and all code that uses code should be removed when the + * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to + * SCSI low-level driver detect, queuecommand, and reset entrypoints. + * + * The interrupt flags values doesn't matter in the macros because the + * SCSI mid-level will save and restore the flags values before and after + * calling advansys_detect, advansys_queuecommand, and advansys_reset where + * these macros are used. We do want interrupts enabled after the lock is + * released so an explicit sti() is done. The driver only needs interrupts + * disabled when it acquires the per board lock. + */ +#define ASC_UNLOCK_IO_REQUEST_LOCK \ + { \ + ulong flags; /* flags value not needed, cf. comment above. */ \ + save_flags(flags); \ + spin_unlock_irqrestore(&io_request_lock, flags); \ + sti(); /* enable interrupts */ \ + } + +#define ASC_LOCK_IO_REQUEST_LOCK \ + { \ + ulong flags; /* flags value not needed, cf. comment above. */ \ + spin_lock_irqsave(&io_request_lock, flags); \ + } /* Asc Library return codes */ #define ASC_TRUE 1 @@ -3627,12 +3764,13 @@ #define PCI_MAX_BUS 0xFF #define PCI_IOADDRESS_MASK 0xFFFE #define ASC_PCI_VENDORID 0x10CD -#define ASC_PCI_DEVICE_ID_CNT 5 /* PCI Device ID count. */ +#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */ #define ASC_PCI_DEVICE_ID_1100 0x1100 #define ASC_PCI_DEVICE_ID_1200 0x1200 #define ASC_PCI_DEVICE_ID_1300 0x1300 #define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */ #define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */ +#define ASC_PCI_DEVICE_ID_2700 0x2700 /* ASC-38C1600 */ /* PCI IO Port Addresses to generate special cycle */ @@ -3843,10 +3981,8 @@ /* Per board statistics structure */ struct asc_stats { /* Driver Entrypoint Statistics */ - ADV_DCNT command; /* # calls to advansys_command() */ ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */ - ADV_DCNT abort; /* # calls to advansys_abort() */ - ADV_DCNT reset; /* # calls to advansys_reset() */ + ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */ ADV_DCNT biosparam; /* # calls to advansys_biosparam() */ ADV_DCNT interrupt; /* # advansys_interrupt() calls */ ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */ @@ -3899,16 +4035,18 @@ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux * up to 255 scatter-gather elements may be used per request or * ADV_SCSI_REQ_Q. + * + * Both structures must be 32 byte aligned. */ typedef struct adv_sgblk { - ADV_SG_BLOCK sg_block; /* Sgblock structure. */ - uchar align2[4]; /* Sgblock structure padding. */ - struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ + ADV_SG_BLOCK sg_block; /* Sgblock structure. */ + uchar align[32]; /* Sgblock structure padding. */ + struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ } adv_sgblk_t; typedef struct adv_req { ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ - uchar align1[4]; /* Request structure padding. */ + uchar align[32]; /* Request structure padding. */ Scsi_Cmnd *cmndp; /* Mid-Level SCSI command pointer. */ adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ struct adv_req *next_reqp; /* Next Request Structure. */ @@ -3932,6 +4070,7 @@ ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */ ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ } dvc_cfg; + ushort asc_n_io_port; /* Number I/O ports. */ asc_queue_t active; /* Active command queue */ asc_queue_t waiting; /* Waiting command queue */ asc_queue_t done; /* Done command queue */ @@ -3944,12 +4083,14 @@ ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */ ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */ + ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */ } eep_config; ulong last_reset; /* Saved last reset time */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + spinlock_t lock; /* Board spinlock */ +#ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] */ - char *prtbuf; /* Statistics Print Buffer */ -#endif /* version >= v1.3.0 */ + char *prtbuf; /* /proc print buffer */ +#endif /* CONFIG_PROC_FS */ #ifdef ADVANSYS_STATS struct asc_stats asc_stats; /* Board statistics */ #endif /* ADVANSYS_STATS */ @@ -4032,8 +4173,8 @@ /* Note: All driver global data should be initialized. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) && \ - LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#if ASC_LINUX_KERNEL22 +#ifdef CONFIG_PROC_FS struct proc_dir_entry proc_scsi_advansys = { PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ @@ -4042,13 +4183,14 @@ S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ 2 /* nlink_t nlink */ }; -#endif /* v2.3.28 > version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ +#endif /* ASC_LINUX_KERNEL22 */ /* Number of boards detected in system. */ STATIC int asc_board_count = 0; STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; -/* Overrun buffer shared between all boards. */ +/* Overrun buffer used by all narrow boards. */ STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; /* @@ -4065,12 +4207,6 @@ ASC_IS_PCI, }; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI -STATIC int pci_scan_method ASC_INITDATA = -1; -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ - /* * Used with the LILO 'advansys' option to eliminate or * limit I/O port probing at boot time, cf. advansys_setup(). @@ -4078,19 +4214,6 @@ STATIC int asc_iopflag = ASC_FALSE; STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 }; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -/* - * In kernels earlier than v1.3.0, kmalloc() does not work - * during driver initialization. Therefore statically declare - * 16 elements of each structure. v1.3.0 kernels will probably - * not need any more than this number. - */ -uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 }; -uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 }; -#define ADV_SGBLK_BUF_CNT 32 -uchar adv_sgblk_buf[ADV_SGBLK_BUF_CNT * sizeof(adv_sgblk_t)] = { 0 }; -#endif /* version >= v1,3,0 */ - #ifdef ADVANSYS_DEBUG STATIC char * asc_bus_name[ASC_NUM_BUS] = { @@ -4100,7 +4223,7 @@ "ASC_IS_PCI", }; -STATIC int asc_dbglvl = 2; +STATIC int asc_dbglvl = 3; #endif /* ADVANSYS_DEBUG */ /* Declaration for Asc Library internal data referenced by driver. */ @@ -4113,19 +4236,9 @@ * advansys.h contains function prototypes for functions global to Linux. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) -STATIC void advansys_interrupt(int, struct pt_regs *); -#else /* version >= v1.3.70 */ -STATIC void advansys_interrupt(int, void *, struct pt_regs *); -#endif /* version >= v1.3.70 */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC void advansys_select_queue_depths(struct Scsi_Host *, - Scsi_Device *); -#endif /* version >= v1.3.89 */ -STATIC void advansys_command_done(Scsi_Cmnd *); +STATIC void advansys_interrupt(int, void *, struct pt_regs *); +STATIC void advansys_select_queue_depths(struct Scsi_Host *, + Scsi_Device *); STATIC void asc_scsi_done_list(Scsi_Cmnd *); STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *); @@ -4134,24 +4247,13 @@ STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); STATIC void adv_async_callback(ADV_DVC_VAR *, uchar); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI -STATIC int asc_srch_pci_dev(PCI_DEVICE *); -STATIC uchar asc_scan_method(void); -STATIC int asc_pci_find_dev(PCI_DEVICE *); -STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); -STATIC ushort asc_get_cfg_word(PCI_DATA *); -STATIC uchar asc_get_cfg_byte(PCI_DATA *); -STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ STATIC void asc_enqueue(asc_queue_t *, REQP, int); STATIC REQP asc_dequeue(asc_queue_t *, int); STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int); STATIC int asc_rmqueue(asc_queue_t *, REQP); -STATIC int asc_isqueued(asc_queue_t *, REQP); STATIC void asc_execute_queue(asc_queue_t *); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS +STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int); STATIC int asc_prt_adv_bios(struct Scsi_Host *, char *, int); STATIC int asc_get_eeprom_string(ushort *serialnum, uchar *cp); @@ -4161,16 +4263,21 @@ STATIC int asc_prt_asc_board_info(struct Scsi_Host *, char *, int); STATIC int asc_prt_adv_board_info(struct Scsi_Host *, char *, int); STATIC int asc_prt_line(char *, int, char *fmt, ...); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ /* Declaration for Asc Library internal functions referenced by driver. */ STATIC int AscFindSignature(PortAddr); STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); +/* Statistics function prototypes. */ #ifdef ADVANSYS_STATS +#ifdef CONFIG_PROC_FS STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); +STATIC int asc_prt_target_stats(struct Scsi_Host *, int, char *, int); +#endif /* CONFIG_PROC_FS */ #endif /* ADVANSYS_STATS */ +/* Debug function prototypes. */ #ifdef ADVANSYS_DEBUG STATIC void asc_prt_scsi_host(struct Scsi_Host *); STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *); @@ -4185,16 +4292,12 @@ STATIC void asc_prt_hex(char *f, uchar *, int); #endif /* ADVANSYS_DEBUG */ -#ifdef ADVANSYS_ASSERT -STATIC int advansys_interrupts_enabled(void); -#endif /* ADVANSYS_ASSERT */ - /* * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS /* * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] * @@ -4216,10 +4319,9 @@ * user just won't get all the available statistics. */ int -advansys_proc_info(char *buffer, char **start, off_t offset, int length, +advansys_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { -#ifdef CONFIG_PROC_FS struct Scsi_Host *shp; asc_board_t *boardp; int i; @@ -4231,6 +4333,9 @@ char *curbuf; off_t advoffset; Scsi_Device *scd; +#ifdef ADVANSYS_STATS + int tgt_id; +#endif /* ADVANSYS_STATS */ ASC_DBG(1, "advansys_proc_info: begin\n"); @@ -4322,11 +4427,7 @@ * Display target driver information for each device attached * to the board. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) - for (scd = scsi_devices; scd; scd = scd->next) -#else /* version >= v2.1.75 */ for (scd = shp->host_queue; scd; scd = scd->next) -#endif /* version >= v2.1.75 */ { if (scd->host == shp) { cp = boardp->prtbuf; @@ -4347,7 +4448,7 @@ curbuf += cnt; } } - + /* * Display EEPROM configuration for the board. */ @@ -4390,7 +4491,7 @@ */ cp = boardp->prtbuf; cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; leftlen -= cnt; @@ -4400,6 +4501,24 @@ } advoffset += cplen; curbuf += cnt; + + /* + * Display driver statistics for each target. + */ + for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) { + cp = boardp->prtbuf; + cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + } #endif /* ADVANSYS_STATS */ /* @@ -4426,11 +4545,8 @@ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); return totcnt; -#else /* CONFIG_PROC_FS */ - return 0; -#endif /* CONFIG_PROC_FS */ } -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ /* * advansys_detect() @@ -4461,19 +4577,6 @@ int ioport = 0; int share_irq = FALSE; int iolen = 0; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - int pci_init_search = 0; - PCI_DEVICE pci_device[ASC_NUM_BOARD_SUPPORTED]; - int pci_card_cnt_max = 0; - int pci_card_cnt = 0; - PCI_DEVICE pciDevice; - PCI_CONFIG_SPACE pciConfig; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - ADV_PADDR pci_memory_address; -#endif /* version >= v1,3,0 */ -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI int pci_init_search = 0; struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED]; @@ -4486,11 +4589,11 @@ ASC_PCI_DEVICE_ID_1200, ASC_PCI_DEVICE_ID_1300, ASC_PCI_DEVICE_ID_2300, - ASC_PCI_DEVICE_ID_2500 + ASC_PCI_DEVICE_ID_2500, + ASC_PCI_DEVICE_ID_2700 }; ADV_PADDR pci_memory_address; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ int warn_code, err_code; int ret; @@ -4503,11 +4606,18 @@ ASC_DBG(1, "advansys_detect: begin\n"); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,28) + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level detect entrypoint. + */ + ASC_UNLOCK_IO_REQUEST_LOCK + +#if ASC_LINUX_KERNEL24 tpnt->proc_name = "advansys"; -#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#elif ASC_LINUX_KERNEL22 tpnt->proc_dir = &proc_scsi_advansys; -#endif /* version >= v1.3.0 */ +#endif asc_board_count = 0; @@ -4517,7 +4627,7 @@ */ if (asc_iopflag == ASC_TRUE) { for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { - ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n", + ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n", ioport, asc_ioport[ioport]); if (asc_ioport[ioport] != 0) { for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) { @@ -4536,15 +4646,6 @@ ioport = 0; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - memset(&pciDevice, 0, sizeof(PCI_DEVICE)); - memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE)); - pciDevice.maxBusNumber = PCI_MAX_BUS; - pciDevice.endSlot = PCI_MAX_SLOT; -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ - for (bus = 0; bus < ASC_NUM_BUS; bus++) { ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n", @@ -4559,6 +4660,7 @@ switch (asc_bus[bus]) { case ASC_IS_ISA: case ASC_IS_VL: +#ifdef CONFIG_ISA if (asc_iopflag == ASC_FALSE) { iop = AscSearchIOPortAddr(iop, asc_bus[bus]); } else { @@ -4577,7 +4679,8 @@ } } if (iop) { - ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n", + ASC_DBG1(1, + "advansys_detect: probing I/O port 0x%x...\n", iop); if (check_region(iop, ASC_IOADR_GAP) != 0) { printk( @@ -4618,74 +4721,16 @@ asc_ioport[ioport++] = 0; } } +#endif /* CONFIG_ISA */ break; case ASC_IS_EISA: +#ifdef CONFIG_ISA iop = AscSearchIOPortAddr(iop, asc_bus[bus]); +#endif /* CONFIG_ISA */ break; case ASC_IS_PCI: -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - if (pci_init_search == 0) { - int i, j; - - pci_init_search = 1; - - /* Find all PCI cards. */ - while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) { - pci_device[pci_card_cnt_max++] = pciDevice; - } - - /* - * Sort PCI cards in ascending order by PCI Bus, Slot, - * and Device Number. - */ - for (i = 0; i < pci_card_cnt_max - 1; i++) - { - for (j = i + 1; j < pci_card_cnt_max; j++) { - if ((pci_device[j].busNumber < - pci_device[i].busNumber) || - ((pci_device[j].busNumber == - pci_device[i].busNumber) && - (pci_device[j].slotNumber < - pci_device[i].slotNumber)) || - ((pci_device[j].busNumber == - pci_device[i].busNumber) && - (pci_device[j].slotNumber == - pci_device[i].slotNumber) && - (pci_device[j].devFunc < - pci_device[i].devFunc))) { - pciDevice = pci_device[i]; - pci_device[i] = pci_device[j]; - pci_device[j] = pciDevice; - } - } - } - - pci_card_cnt = 0; - } else { - pci_card_cnt++; - } - - if (pci_card_cnt == pci_card_cnt_max) { - iop = 0; - } else { - pciDevice = pci_device[pci_card_cnt]; - ASC_DBG2(2, - "advansys_detect: slotFound %d, busNumber %d\n", - pciDevice.slotFound, pciDevice.busNumber); - asc_get_pci_cfg(&pciDevice, &pciConfig); - iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK; - ASC_DBG2(1, - "advansys_detect: vendorID %X, deviceID %X\n", - pciConfig.vendorID, pciConfig.deviceID); - ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n", - iop, pciConfig.irqLine); - } - break; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (pci_init_search == 0) { int i, j; @@ -4699,8 +4744,13 @@ NULL) { pci_device_id_cnt++; } else { - if (pci_enable_device(pci_devp) == 0) - pci_devicep[pci_card_cnt_max++] = pci_devp; +#if ASC_LINUX_KERNEL24 + if (pci_enable_device(pci_devp) == 0) { + pci_devicep[pci_card_cnt_max++] = pci_devp; + } +#elif ASC_LINUX_KERNEL22 + pci_devicep[pci_card_cnt_max++] = pci_devp; +#endif } } @@ -4737,11 +4787,11 @@ ASC_DBG2(2, "advansys_detect: devfn %d, bus number %d\n", pci_devp->devfn, pci_devp->bus->number); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) - iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; -#else /* version >= v2.3.13 */ +#if ASC_LINUX_KERNEL24 iop = pci_resource_start(pci_devp, 0); -#endif /* version >= v2.3.13 */ +#elif ASC_LINUX_KERNEL22 + iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; +#endif ASC_DBG2(1, "advansys_detect: vendorID %X, deviceID %X\n", pci_devp->vendor, pci_devp->device); @@ -4749,7 +4799,6 @@ iop, pci_devp->irq); } #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ break; default: @@ -4757,7 +4806,7 @@ asc_bus[bus]); break; } - ASC_DBG1(1, "advansys_detect: iop %x\n", iop); + ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop); /* * Adapter not found, try next bus type. @@ -4774,9 +4823,10 @@ */ ASC_DBG(2, "advansys_detect: scsi_register()\n"); shp = scsi_register(tpnt, sizeof(asc_board_t)); - - if(shp==NULL) - continue; + + if (shp == NULL) { + continue; + } /* Save a pointer to the Scsi_host of each board found. */ asc_host[asc_board_count++] = shp; @@ -4786,6 +4836,9 @@ memset(boardp, 0, sizeof(asc_board_t)); boardp->id = asc_board_count - 1; + /* Initialize spinlock. */ + boardp->lock = SPIN_LOCK_UNLOCKED; + /* * Handle both narrow and wide boards. * @@ -4793,25 +4846,15 @@ * wide board flag. Set-up the board structure based on * the board type. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - if (asc_bus[bus] == ASC_IS_PCI && - (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 || - pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500)) - { - boardp->flags |= ASC_IS_WIDE_BOARD; - } -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (asc_bus[bus] == ASC_IS_PCI && (pci_devp->device == ASC_PCI_DEVICE_ID_2300 || - pci_devp->device == ASC_PCI_DEVICE_ID_2500)) + pci_devp->device == ASC_PCI_DEVICE_ID_2500 || + pci_devp->device == ASC_PCI_DEVICE_ID_2700)) { boardp->flags |= ASC_IS_WIDE_BOARD; } #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ if (ASC_NARROW_BOARD(boardp)) { ASC_DBG(1, "advansys_detect: narrow board\n"); @@ -4829,36 +4872,22 @@ adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; adv_dvc_varp->isr_callback = adv_isr_callback; adv_dvc_varp->async_callback = adv_async_callback; - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) - { - ASC_DBG(1, "advansys_detect: ASC-3550\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; - } else - { - ASC_DBG(1, "advansys_detect: ASC-38C0800\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; - } -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI if (pci_devp->device == ASC_PCI_DEVICE_ID_2300) { ASC_DBG(1, "advansys_detect: ASC-3550\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; - } else + } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500) { ASC_DBG(1, "advansys_detect: ASC-38C0800\n"); adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; + } else + { + ASC_DBG(1, "advansys_detect: ASC-38C1600\n"); + adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600; } #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - adv_dvc_varp->iop_base = iop; -#else /* version >= v1,3,0 */ /* * Map the board's registers into virtual memory for * PCI slave access. Only memory accesses are used to @@ -4873,76 +4902,53 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { iolen = ADV_3550_IOLEN; - } else { + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { iolen = ADV_38C0800_IOLEN; + } else + { + iolen = ADV_38C1600_IOLEN; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - pci_memory_address = pciConfig.baseAddress[1]; - ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n", - (ulong) pci_memory_address); - if ((boardp->ioremap_addr = - ioremap(pci_memory_address & PAGE_MASK, - PAGE_SIZE)) == 0) { - ASC_PRINT3( -"advansys_detect: board %d: ioremap(%lu, %x) returned NULL\n", - boardp->id, (ulong) pci_memory_address, iolen); - scsi_unregister(shp); - asc_board_count--; - continue; - } - ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n", - (ulong) boardp->ioremap_addr); - adv_dvc_varp->iop_base = (AdvPortAddr) - (boardp->ioremap_addr + - (pci_memory_address - (pci_memory_address & PAGE_MASK))); - ASC_DBG1(1, "advansys_detect: iop_base: %lx\n", - adv_dvc_varp->iop_base); -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) - pci_memory_address = pci_devp->base_address[1]; -#else /* version >= v2.3.13 */ +#if ASC_LINUX_KERNEL24 pci_memory_address = pci_resource_start(pci_devp, 1); -#endif /* version >= v2.3.13 */ - ASC_DBG1(1, "advansys_detect: pci_memory_address: %x\n", - pci_memory_address); +#elif ASC_LINUX_KERNEL22 + pci_memory_address = pci_devp->base_address[1]; +#endif + ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n", + (ulong) pci_memory_address); if ((boardp->ioremap_addr = ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) { ASC_PRINT3( "advansys_detect: board %d: ioremap(%x, %d) returned NULL\n", - boardp->id, pci_memory_address, iolen); + boardp->id, pci_memory_address, iolen); scsi_unregister(shp); asc_board_count--; continue; } - ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n", + ASC_DBG1(1, "advansys_detect: ioremap_addr: 0x%lx\n", (ulong) boardp->ioremap_addr); adv_dvc_varp->iop_base = (AdvPortAddr) (boardp->ioremap_addr + (pci_memory_address - (pci_memory_address & PAGE_MASK))); - ASC_DBG1(1, "advansys_detect: iop_base: %lx\n", + ASC_DBG1(1, "advansys_detect: iop_base: 0x%lx\n", adv_dvc_varp->iop_base); #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ -#endif /* version >= v1,3,0 */ /* - * Even though it isn't used to access the board in - * kernels greater than or equal to v1.3.0, save - * the I/O Port address so that it can be reported and - * displayed. + * Even though it isn't used to access wide boards, other + * than for the debug line below, save I/O Port address so + * that it can be reported. */ boardp->ioport = iop; ASC_DBG2(1, - "advansys_detect: iopb_chip_id_1 %x, iopw_chip_id_0 %x\n", +"advansys_detect: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n", (ushort) inp(iop + 1), (ushort) inpw(iop)); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS /* * Allocate buffer for printing information from * /proc/scsi/advansys/[0...]. @@ -4956,7 +4962,7 @@ asc_board_count--; continue; } -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ if (ASC_NARROW_BOARD(boardp)) { /* @@ -4964,6 +4970,7 @@ * calling AscInitGetConfig(). */ switch (asc_dvc_varp->bus_type) { +#ifdef CONFIG_ISA case ASC_IS_ISA: shp->unchecked_isa_dma = TRUE; share_irq = FALSE; @@ -4976,20 +4983,7 @@ shp->unchecked_isa_dma = FALSE; share_irq = TRUE; break; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - case ASC_IS_PCI: - shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; - asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; - asc_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); - shp->unchecked_isa_dma = FALSE; - share_irq = TRUE; - break; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ +#endif /* CONFIG_ISA */ #ifdef CONFIG_PCI case ASC_IS_PCI: shp->irq = asc_dvc_varp->irq_no = pci_devp->irq; @@ -5002,7 +4996,6 @@ share_irq = TRUE; break; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ default: ASC_PRINT2( "advansys_detect: board %d: unknown adapter type: %d\n", @@ -5016,18 +5009,6 @@ * For Wide boards set PCI information before calling * AdvInitGetConfig(). */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine; - adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; - adv_dvc_varp->cfg->pci_slot_info = - ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); - shp->unchecked_isa_dma = FALSE; - share_irq = TRUE; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI shp->irq = adv_dvc_varp->irq_no = pci_devp->irq; adv_dvc_varp->cfg->pci_device_id = pci_devp->device; @@ -5038,7 +5019,6 @@ shp->unchecked_isa_dma = FALSE; share_irq = TRUE; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -5082,33 +5062,33 @@ break; default: ASC_PRINT2( -"AscInitGetConfig: board %d: unknown warning: %x\n", +"AscInitGetConfig: board %d: unknown warning: 0x%x\n", boardp->id, ret); break; } if ((err_code = asc_dvc_varp->err_code) != 0) { ASC_PRINT3( -"AscInitGetConfig: board %d error: init_state %x, err_code %x\n", +"AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n", boardp->id, asc_dvc_varp->init_state, asc_dvc_varp->err_code); } } else { ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n"); if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) { - ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n", + ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n", boardp->id, ret); } if ((err_code = adv_dvc_varp->err_code) != 0) { ASC_PRINT2( -"AdvInitGetConfig: board %d error: err_code %x\n", +"AdvInitGetConfig: board %d error: err_code 0x%x\n", boardp->id, adv_dvc_varp->err_code); } } - + if (err_code != 0) { -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5136,12 +5116,12 @@ ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable; ep->disc_enable = asc_dvc_varp->cfg->disc_enable; ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; - ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; + ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed); ep->start_motor = asc_dvc_varp->start_motor; ep->cntl = asc_dvc_varp->dvc_cntl; ep->no_scam = asc_dvc_varp->no_scam; ep->max_total_qng = asc_dvc_varp->max_total_qng; - ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; + ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id); /* 'max_tag_qng' is set to the same value for every device. */ ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0]; @@ -5186,18 +5166,18 @@ break; default: ASC_PRINT2( -"AscInitSetConfig: board %d: unknown warning: %x\n", +"AscInitSetConfig: board %d: unknown warning: 0x%x\n", boardp->id, ret); break; } if (asc_dvc_varp->err_code != 0) { ASC_PRINT3( -"AscInitSetConfig: board %d error: init_state %x, err_code %x\n", +"AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n", boardp->id, asc_dvc_varp->init_state, asc_dvc_varp->err_code); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5213,6 +5193,7 @@ } else { ADVEEP_3550_CONFIG *ep_3550; ADVEEP_38C0800_CONFIG *ep_38C0800; + ADVEEP_38C1600_CONFIG *ep_38C1600; /* * Save Wide EEP Configuration Information. @@ -5239,7 +5220,7 @@ adv_dvc_varp->cfg->serial2; ep_3550->serial_number_word3 = adv_dvc_varp->cfg->serial3; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; @@ -5266,6 +5247,33 @@ adv_dvc_varp->cfg->serial2; ep_38C0800->serial_number_word3 = adv_dvc_varp->cfg->serial3; + } else + { + ep_38C1600 = &boardp->eep_config.adv_38C1600_eep; + + ep_38C1600->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; + ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng; + ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng; + ep_38C1600->termination_lvd = + adv_dvc_varp->cfg->termination; + ep_38C1600->disc_enable = adv_dvc_varp->cfg->disc_enable; + ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl; + ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able; + ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able; + ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1; + ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2; + ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3; + ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4; + ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able; + ep_38C1600->start_motor = adv_dvc_varp->start_motor; + ep_38C1600->scsi_reset_delay = + adv_dvc_varp->scsi_reset_wait; + ep_38C1600->serial_number_word1 = + adv_dvc_varp->cfg->serial1; + ep_38C1600->serial_number_word2 = + adv_dvc_varp->cfg->serial2; + ep_38C1600->serial_number_word3 = + adv_dvc_varp->cfg->serial3; } /* @@ -5280,20 +5288,18 @@ shp->irq = adv_dvc_varp->irq_no; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) /* - * Channels are numbered beginning with 0. For AdvanSys One host + * Channels are numbered beginning with 0. For AdvanSys one host * structure supports one channel. Multi-channel boards have a - * separate host structure for each channel. + * separate host structure for each channel. */ shp->max_channel = 0; -#endif /* version >= v1.3.89 */ if (ASC_NARROW_BOARD(boardp)) { shp->max_id = ASC_MAX_TID + 1; shp->max_lun = ASC_MAX_LUN + 1; shp->io_port = asc_dvc_varp->iop_base; - shp->n_io_port = ASC_IOADR_GAP; + boardp->asc_n_io_port = ASC_IOADR_GAP; shp->this_id = asc_dvc_varp->cfg->chip_scsi_id; /* Set maximum number of queues the adapter can handle. */ @@ -5303,13 +5309,13 @@ shp->max_lun = ADV_MAX_LUN + 1; /* - * Save the I/O Port address and length even though the - * in v1.3.0 and greater kernels the region is not used - * by a Wide board. Instead the board is accessed with - * Memory Mapped I/O. + * Save the I/O Port address and length even though + * I/O ports are not used to access Wide boards. + * Instead the Wide boards are accessed with + * PCI Memory Mapped I/O. */ shp->io_port = iop; - shp->n_io_port = iolen; + boardp->asc_n_io_port = iolen; shp->this_id = adv_dvc_varp->chip_scsi_id; @@ -5317,18 +5323,15 @@ shp->can_queue = adv_dvc_varp->max_host_qng; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) /* - * In old kernels without tag queuing support and with memory - * allocation problems set a conservative 'cmd_per_lun' value. + * 'n_io_port' currently is one byte. + * + * Set a value to 'n_io_port', but never referenced it because + * it may be truncated. */ -#ifdef MODULE - shp->cmd_per_lun = 1; -#else /* MODULE */ - shp->cmd_per_lun = 4; -#endif /* MODULE */ - ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); -#else /* version >= v1.3.89 */ + shp->n_io_port = boardp->asc_n_io_port <= 255 ? + boardp->asc_n_io_port : 255; + /* * Following v1.3.89, 'cmd_per_lun' is no longer needed * and should be set to zero. @@ -5348,7 +5351,6 @@ * the number of commands to queue per device. */ shp->select_queue_depths = advansys_select_queue_depths; -#endif /* version >= v1.3.89 */ /* * Set the maximum number of scatter-gather elements the @@ -5368,20 +5370,6 @@ shp->sg_tablesize = ADV_MAX_SG_LIST; } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) -#ifdef MODULE - /* - * If the driver is compiled as a module, set a limit on the - * 'sg_tablesize' value to prevent memory allocation failures. - * Memory allocation errors are more likely to occur at module - * load time, then at driver initialization time. - */ - if (shp->sg_tablesize > 64) { - shp->sg_tablesize = 64; - } -#endif /* MODULE */ -#endif /* version < v2.0.0 */ - /* * The value of 'sg_tablesize' can not exceed the SCSI * mid-level driver definition of SG_ALL. SG_ALL also @@ -5397,11 +5385,11 @@ /* BIOS start address. */ if (ASC_NARROW_BOARD(boardp)) { -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29) +#if ASC_LINUX_KERNEL24 shp->base = -#else /* version >= v2.3.29 */ +#elif ASC_LINUX_KERNEL22 shp->base = (char *) -#endif /* version < v2.3.29 */ +#endif ((ulong) AscGetChipBiosAddress( asc_dvc_varp->iop_base, asc_dvc_varp->bus_type)); @@ -5420,11 +5408,11 @@ boardp->bios_codelen); ASC_DBG2(1, - "advansys_detect: bios_signature %x, bios_version %x\n", + "advansys_detect: bios_signature 0x%x, bios_version 0x%x\n", boardp->bios_signature, boardp->bios_version); ASC_DBG2(1, - "advansys_detect: bios_codeseg %x, bios_codelen %x\n", + "advansys_detect: bios_codeseg 0x%x, bios_codelen 0x%x\n", boardp->bios_codeseg, boardp->bios_codelen); /* @@ -5436,11 +5424,10 @@ * Convert x86 realmode code segment to a linear * address by shifting left 4. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29) shp->base = -#else /* version >= v2.3.29 */ - shp->base = (char *) -#endif /* version < v2.3.29 */ +#if ASC_LINUX_KERNEL22 + (char *) +#endif ((ulong) boardp->bios_codeseg << 4); } else { shp->base = 0; @@ -5451,12 +5438,37 @@ * Register Board Resources - I/O Port, DMA, IRQ */ - /* Register I/O port range. */ - ASC_DBG(2, "advansys_detect: request_region()\n"); - request_region(shp->io_port, shp->n_io_port, "advansys"); + /* + * Register I/O port range. + * + * For Wide boards the I/O ports are not used to access + * the board, but request the region anyway. + * + * 'shp->n_io_port' is not referenced, because it may be truncated. + */ + ASC_DBG2(2, + "advansys_detect: request_region port 0x%lx, len 0x%x\n", + (ulong) shp->io_port, boardp->asc_n_io_port); +#if ASC_LINUX_KERNEL24 + if (request_region(shp->io_port, boardp->asc_n_io_port, + "advansys") == NULL) { + ASC_PRINT3( +"advansys_detect: board %d: request_region() failed, port 0x%lx, len 0x%x\n", + boardp->id, (ulong) shp->io_port, boardp->asc_n_io_port); +#ifdef CONFIG_PROC_FS + kfree(boardp->prtbuf); +#endif /* CONFIG_PROC_FS */ + scsi_unregister(shp); + asc_board_count--; + continue; + } +#elif ASC_LINUX_KERNEL22 + request_region(shp->io_port, boardp->asc_n_io_port, "advansys"); +#endif /* Register DMA Channel for Narrow boards. */ shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */ +#ifdef CONFIG_ISA if (ASC_NARROW_BOARD(boardp)) { /* Register DMA channel for ISA bus. */ if (asc_dvc_varp->bus_type & ASC_IS_ISA) { @@ -5466,10 +5478,10 @@ ASC_PRINT3( "advansys_detect: board %d: request_dma() %d failed %d\n", boardp->id, shp->dma_channel, ret); - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5477,13 +5489,10 @@ AscEnableIsaDma(shp->dma_channel); } } +#endif /* CONFIG_ISA */ /* Register IRQ Number. */ ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT, "advansys")) != 0) -#else /* version >= v1.3.70 */ /* * If request_irq() fails with the SA_INTERRUPT flag set, * then try again without the SA_INTERRUPT flag set. This @@ -5499,31 +5508,28 @@ ((ret = request_irq(shp->irq, advansys_interrupt, (share_irq == TRUE ? SA_SHIRQ : 0), "advansys", boardp)) != 0)) -#endif /* version >= v1.3.70 */ { if (ret == -EBUSY) { ASC_PRINT2( -"advansys_detect: board %d: request_irq(): IRQ %d already in use.\n", +"advansys_detect: board %d: request_irq(): IRQ 0x%x already in use.\n", boardp->id, shp->irq); } else if (ret == -EINVAL) { ASC_PRINT2( -"advansys_detect: board %d: request_irq(): IRQ %d not valid.\n", +"advansys_detect: board %d: request_irq(): IRQ 0x%x not valid.\n", boardp->id, shp->irq); } else { ASC_PRINT3( -"advansys_detect: board %d: request_irq(): IRQ %d failed with %d\n", +"advansys_detect: board %d: request_irq(): IRQ 0x%x failed with %d\n", boardp->id, shp->irq, ret); } - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); iounmap(boardp->ioremap_addr); -#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); asc_board_count--; continue; @@ -5539,7 +5545,7 @@ if (warn_code || err_code) { ASC_PRINT4( -"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n", +"advansys_detect: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n", boardp->id, asc_dvc_varp->init_state, warn_code, err_code); } @@ -5549,25 +5555,13 @@ adv_req_t *reqp = NULL; int sg_cnt = 0; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) - carrp = (ADV_CARR_T *) &adv_carr_buf[0]; - req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t); - sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t); - reqp = (adv_req_t *) &adv_req_buf[0]; - boardp->adv_sgblkp = NULL; - for (sg_cnt = 0; sg_cnt < ADV_SGBLK_BUF_CNT; sg_cnt++) { - sgp = (adv_sgblk_t *) &adv_sgblk_buf[sg_cnt]; - sgp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgp; - } -#else /* version >= v1.3.0 */ /* * Allocate buffer carrier structures. The total size * is about 4 KB, so allocate all at once. */ carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC); - ASC_DBG1(1, "advansys_detect: carrp %lx\n", (ulong) carrp); + ASC_DBG1(1, "advansys_detect: carrp 0x%lx\n", (ulong) carrp); if (carrp == NULL) { goto kmalloc_error; @@ -5586,7 +5580,7 @@ kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC); ASC_DBG3(1, - "advansys_detect: reqp %lx, req_cnt %d, bytes %lu\n", + "advansys_detect: reqp 0x%lx, req_cnt %d, bytes %lu\n", (ulong) reqp, req_cnt, (ulong) sizeof(adv_req_t) * req_cnt); @@ -5631,24 +5625,24 @@ if (carrp == NULL) { ASC_PRINT1( -"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n", +"advansys_detect: board %d error: failed to kmalloc() carrier buffer.\n", boardp->id); err_code = ADV_ERROR; } else if (reqp == NULL) { kfree(carrp); ASC_PRINT1( -"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n", +"advansys_detect: board %d error: failed to kmalloc() adv_req_t buffer.\n", boardp->id); err_code = ADV_ERROR; } else if (boardp->adv_sgblkp == NULL) { kfree(carrp); kfree(reqp); ASC_PRINT1( -"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffers.\n", +"advansys_detect: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n", boardp->id); err_code = ADV_ERROR; } else { - + /* Save carrier buffer pointer. */ boardp->orig_carrp = carrp; @@ -5657,7 +5651,6 @@ * driver is built as a module and can be unloaded. */ boardp->orig_reqp = reqp; -#endif /* version >= v1.3.0 */ adv_dvc_varp->carrier_buf = carrp; @@ -5677,26 +5670,27 @@ ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n"); warn_code = AdvInitAsc3550Driver(adv_dvc_varp); - } else { + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { ASC_DBG(2, "advansys_detect: AdvInitAsc38C0800Driver()\n"); warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp); + } else { + ASC_DBG(2, + "advansys_detect: AdvInitAsc38C1600Driver()\n"); + warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp); } err_code = adv_dvc_varp->err_code; if (warn_code || err_code) { ASC_PRINT3( -"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n", +"advansys_detect: board %d error: warn 0x%x, error 0x%x\n", boardp->id, warn_code, err_code); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) } -#endif /* version >= v1,3,0 */ } if (err_code != 0) { - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); if (ASC_WIDE_BOARD(boardp)) { iounmap(boardp->ioremap_addr); if (boardp->orig_carrp) { @@ -5713,18 +5707,13 @@ kfree(sgp); } } -#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - free_irq(shp->irq); -#else /* version >= v1.3.70 */ +#endif /* CONFIG_PROC_FS */ free_irq(shp->irq, boardp); -#endif /* version >= v1.3.70 */ scsi_unregister(shp); asc_board_count--; continue; @@ -5732,6 +5721,14 @@ ASC_DBG_PRT_SCSI_HOST(2, shp); } } + + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level detect entrypoint. + */ + ASC_LOCK_IO_REQUEST_LOCK + ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count); return asc_board_count; } @@ -5748,17 +5745,12 @@ ASC_DBG(1, "advansys_release: begin\n"); boardp = ASC_BOARDP(shp); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) - free_irq(shp->irq); -#else /* version >= v1.3.70 */ free_irq(shp->irq, boardp); -#endif /* version >= v1.3.70 */ if (shp->dma_channel != NO_ISA_DMA) { ASC_DBG(1, "advansys_release: free_dma()\n"); free_dma(shp->dma_channel); } - release_region(shp->io_port, shp->n_io_port); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + release_region(shp->io_port, boardp->asc_n_io_port); if (ASC_WIDE_BOARD(boardp)) { adv_sgblk_t *sgp = NULL; @@ -5777,9 +5769,10 @@ kfree(sgp); } } +#ifdef CONFIG_PROC_FS ASC_ASSERT(boardp->prtbuf != NULL); kfree(boardp->prtbuf); -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ scsi_unregister(shp); ASC_DBG(1, "advansys_release: end\n"); return 0; @@ -5815,51 +5808,37 @@ } else { busname = "ISA"; } + /* Don't reference 'shp->n_io_port'; It may be truncated. */ sprintf(info, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92) -"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u", -#else /* version >= v2.1.92 */ -"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u", -#endif /* version >= v2.1.92 */ - ASC_VERSION, busname, asc_dvc_varp->max_total_qng, - (ulong) shp->base, - (ulong) shp->io_port, shp->n_io_port - 1, +"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X", + ASC_VERSION, busname, + (ulong) shp->io_port, + (ulong) shp->io_port + boardp->asc_n_io_port - 1, shp->irq, shp->dma_channel); - } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } - sprintf(info, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92) - "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u", -#else /* version >= v2.1.92 */ - "AdvanSys SCSI %s: %s %u CDB: IO %lX/%X, IRQ %u", -#endif /* version >= v2.1.92 */ - ASC_VERSION, busname, asc_dvc_varp->max_total_qng, - shp->io_port, shp->n_io_port - 1, shp->irq); } else { if (asc_dvc_varp->bus_type & ASC_IS_VL) { busname = "VL"; } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { busname = "EISA"; + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) + == ASC_IS_PCI_ULTRA) { + busname = "PCI Ultra"; + } else { + busname = "PCI"; + } } else { busname = "?"; - ASC_PRINT2( - "advansys_info: board %d: unknown bus type %d\n", + ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n", boardp->id, asc_dvc_varp->bus_type); } + /* Don't reference 'shp->n_io_port'; It may be truncated. */ sprintf(info, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92) - "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %X/%X, IRQ %u", -#else /* version >= v2.1.92 */ - "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u", -#endif /* version >= v2.1.92 */ - ASC_VERSION, busname, asc_dvc_varp->max_total_qng, - (ulong) shp->base, shp->io_port - 1, - shp->n_io_port, shp->irq); + "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X", + ASC_VERSION, busname, + (ulong) shp->io_port, + (ulong) shp->io_port + boardp->asc_n_io_port - 1, + shp->irq); } } else { /* @@ -5874,29 +5853,21 @@ { iolen = ADV_3550_IOLEN; widename = "Ultra-Wide"; - } else { + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { iolen = ADV_38C0800_IOLEN; widename = "Ultra2-Wide"; + } else + { + iolen = ADV_38C1600_IOLEN; + widename = "Ultra3-Wide"; } - if (boardp->bios_signature == 0x55AA) { - sprintf(info, -"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u", - ASC_VERSION, - widename, - boardp->bios_codeseg << 4, - boardp->bios_codelen > 0 ? - (boardp->bios_codelen << 9) - 1 : 0, - (unsigned) boardp->ioport, iolen - 1, - shp->irq); - } else { - sprintf(info, -"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u", - ASC_VERSION, - widename, - (unsigned) boardp->ioport, - (iolen - 1), - shp->irq); - } + sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X", + ASC_VERSION, + widename, + (ulong) adv_dvc_varp->iop_base, + (ulong) adv_dvc_varp->iop_base + iolen - 1, + shp->irq); } ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); ASC_DBG(1, "advansys_info: end\n"); @@ -5904,30 +5875,6 @@ } /* - * advansys_command() - polled I/O entrypoint. - * - * Apparently host drivers shouldn't return until the command - * is finished. - * - * Note: This is an old interface that is no longer used by the SCSI - * mid-level driver. The new interface, advansys_queuecommand(), - * currently handles all requests. - */ -int -advansys_command(Scsi_Cmnd *scp) -{ - ASC_DBG1(1, "advansys_command: scp %lx\n", (ulong) scp); - ASC_STATS(scp->host, command); - scp->SCp.Status = 0; /* Set to a known state */ - advansys_queuecommand(scp, advansys_command_done); - while (scp->SCp.Status == 0) { - continue; - } - ASC_DBG1(1, "advansys_command: result %x\n", scp->result); - return scp->result; -} - -/* * advansys_queuecommand() - interrupt-driven I/O entrypoint. * * This function always returns 0. Command return status is saved @@ -5938,7 +5885,7 @@ { struct Scsi_Host *shp; asc_board_t *boardp; - int flags; + ulong flags; Scsi_Cmnd *done_scp; shp = scp->host; @@ -5946,28 +5893,22 @@ ASC_STATS(shp, queuecommand); /* - * Disable interrupts to preserve request ordering and provide - * mutually exclusive access to global structures used to initiate - * a request. + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level queuecommand entrypoint. */ - save_flags(flags); - cli(); + ASC_UNLOCK_IO_REQUEST_LOCK + + spin_lock_irqsave(&boardp->lock, flags); /* * Block new commands while handling a reset or abort request. */ - if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - if (boardp->flags & ASC_HOST_IN_RESET) { - ASC_DBG1(1, - "advansys_queuecommand: scp %lx blocked for reset request\n", - (ulong) scp); - scp->result = HOST_BYTE(DID_RESET); - } else { - ASC_DBG1(1, - "advansys_queuecommand: scp %lx blocked for abort request\n", - (ulong) scp); - scp->result = HOST_BYTE(DID_ABORT); - } + if (boardp->flags & ASC_HOST_IN_RESET) { + ASC_DBG1(1, + "advansys_queuecommand: scp 0x%lx blocked for reset request\n", + (ulong) scp); + scp->result = HOST_BYTE(DID_RESET); /* * Add blocked requests to the board's 'done' queue. The queued @@ -5975,7 +5916,7 @@ * handling. */ asc_enqueue(&boardp->done, scp, ASC_BACK); - restore_flags(flags); + spin_unlock_irqrestore(&boardp->lock, flags); return 0; } @@ -5992,13 +5933,15 @@ * Save the function pointer to Linux mid-level 'done' function * and attempt to execute the command. * - * If ASC_ERROR is returned the request has been added to the + * If ASC_NOERROR is returned the request has been added to the * board's 'active' queue and will be completed by the interrupt * handler. * * If ASC_BUSY is returned add the request to the board's per - * target waiting list. - * + * target waiting list. This is the first time the request has + * been tried. Add it to the back of the waiting list. It will be + * retried later. + * * If an error occurred, the request will have been placed on the * board's 'done' queue and must be completed before returning. */ @@ -6017,645 +5960,223 @@ break; } - restore_flags(flags); - return 0; -} - -/* - * advansys_abort() - * - * Abort the command specified by 'scp'. - */ -int -advansys_abort(Scsi_Cmnd *scp) -{ - struct Scsi_Host *shp; - asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; - ADV_DVC_VAR *adv_dvc_varp; - int flags; - int do_scsi_done; - int scp_found; - Scsi_Cmnd *done_scp = NULL; - int ret; - - /* Save current flags and disable interrupts. */ - save_flags(flags); - cli(); - - ASC_DBG1(1, "advansys_abort: scp %lx\n", (ulong) scp); - -#ifdef ADVANSYS_STATS - if (scp->host != NULL) { - ASC_STATS(scp->host, abort); - } -#endif /* ADVANSYS_STATS */ - -#ifdef ADVANSYS_ASSERT - do_scsi_done = ASC_ERROR; - scp_found = ASC_ERROR; - ret = ASC_ERROR; -#endif /* ADVANSYS_ASSERT */ - -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (scp->serial_number != scp->serial_number_at_timeout) { - ASC_PRINT1( -"advansys_abort: timeout serial number changed for request %lx\n", - (ulong) scp); - do_scsi_done = ASC_FALSE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_NOT_RUNNING; - } else -#endif /* version >= v1.3.89 */ - if ((shp = scp->host) == NULL) { - scp->result = HOST_BYTE(DID_ERROR); - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_ERROR; - } else if ((boardp = ASC_BOARDP(shp))->flags & - (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - ASC_PRINT2( -"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n", - boardp->id, boardp->flags); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_ABORT_ERROR; - } else { - /* Set abort flag to avoid nested reset or abort requests. */ - boardp->flags |= ASC_HOST_IN_ABORT; - - do_scsi_done = ASC_TRUE; - if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { - /* - * If asc_rmqueue() found the command on the waiting - * queue, it had not been sent to the device. After - * the queue is removed, no other handling is required. - */ - ASC_DBG1(1, "advansys_abort: scp %lx found on waiting queue\n", - (ulong) scp); - scp_found = ASC_TRUE; - scp->result = HOST_BYTE(DID_ABORT); - ret = SCSI_ABORT_SUCCESS; - } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { - /* - * If asc_isqueued() found the command on the active - * queue, it has been sent to the device. The command - * will be returned through the interrupt handler after - * it has been aborted. - */ - - if (ASC_NARROW_BOARD(boardp)) { - /* - * Narrow Board - */ - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - scp->result = HOST_BYTE(DID_ABORT); - - /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */ - ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %lx\n", - (ulong) scp); - /* XXX */ - switch (AscAbortSRB(asc_dvc_varp, ASC_VADDR_TO_U32(scp))) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); - ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; - } - cli(); - } else { - /* - * Wide Board - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - scp->result = HOST_BYTE(DID_ABORT); - - ASC_DBG1(1, - "advansys_abort: before AdvAbortQueue(), scp %lx\n", - (ulong) scp); -#if 0 /* XXX */ - switch (AdvAbortQueue(adv_dvc_varp, (ADV_VADDR) XXX)) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n"); - ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; - } - /* - * Ensure all requests completed by the microcode have - * been processed by calling AdvISR(). - */ - (void) AdvISR(adv_dvc_varp); -#else /* XXX */ - (void) AdvResetChipAndSB(adv_dvc_varp); - ret = SCSI_ABORT_SUCCESS; -#endif /* XXX */ - } - - /* - * The request will either still be on the active queue - * or have been added to the board's done queue. - */ - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - scp->result = HOST_BYTE(DID_ABORT); - scp_found = ASC_TRUE; - } else { - scp_found = asc_rmqueue(&boardp->done, scp); - ASC_ASSERT(scp_found == ASC_TRUE); - } - } else { - /* - * The command was not found on the active or waiting queues. - */ - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_ABORT_NOT_RUNNING; - } - - /* Clear abort flag. */ - boardp->flags &= ~ASC_HOST_IN_ABORT; - - /* - * Because the ASC_HOST_IN_ABORT flag causes both - * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'done' queue and - * prevents waiting commands from being executed, - * these queued requests must be handled here. - */ - done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); - - /* - * Start any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); - } - } - - /* Interrupts could be enabled here. */ - - /* - * Complete the request to be aborted, unless it has been - * restarted as detected above, even if it was not found on - * the device active or waiting queues. - */ - ASC_ASSERT(do_scsi_done != ASC_ERROR); - ASC_ASSERT(scp_found != ASC_ERROR); - if (do_scsi_done == ASC_TRUE) { - if (scp->scsi_done == NULL) { - ASC_PRINT1( -"advansys_abort: aborted request scsi_done() is NULL, %lx\n", - (ulong) scp); - } else { - if (scp_found == ASC_FALSE) { - ASC_PRINT1( -"advansys_abort: abort request not active or waiting, completing anyway %lx\n", - (ulong) scp); - } - ASC_STATS(scp->host, done); - scp->scsi_done(scp); - } - } + spin_unlock_irqrestore(&boardp->lock, flags); /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until all requests have been completed. + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level queuecommand entrypoint. */ - if (done_scp != NULL) { - asc_scsi_done_list(done_scp); - } - - ASC_DBG1(1, "advansys_abort: ret %d\n", ret); - - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); + ASC_LOCK_IO_REQUEST_LOCK - ASC_ASSERT(ret != ASC_ERROR); - return ret; + return 0; } /* * advansys_reset() * - * Reset the device associated with the command 'scp'. + * Reset the bus associated with the command 'scp'. + * + * This function runs its own thread. Interrupts must be blocked but + * sleeping is allowed and no locking other than for host structures is + * required. Returns SUCCESS or FAILED. */ int -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) advansys_reset(Scsi_Cmnd *scp) -#else /* version >= v1.3.89 */ -advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags) -#endif /* version >= v1.3.89 */ { struct Scsi_Host *shp; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; ADV_DVC_VAR *adv_dvc_varp; - int flags; + ulong flags; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *tscp, *new_last_scp; - int do_scsi_done; - int scp_found; int status; - int target; - int ret; - int device_reset = ASC_FALSE; - - /* Save current flags and disable interrupts. */ - save_flags(flags); - cli(); + int ret = SUCCESS; - ASC_DBG1(1, "advansys_reset: %lx\n", (ulong) scp); + ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong) scp); #ifdef ADVANSYS_STATS if (scp->host != NULL) { ASC_STATS(scp->host, reset); - } + } #endif /* ADVANSYS_STATS */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) && - (scp->serial_number != scp->serial_number_at_timeout)) { - ASC_PRINT1( -"advansys_reset: timeout serial number changed for request %lx\n", - (ulong) scp); - do_scsi_done = ASC_FALSE; - scp_found = ASC_FALSE; - ret = SCSI_RESET_NOT_RUNNING; - } else -#endif /* version >= v1.3.89 */ if ((shp = scp->host) == NULL) { scp->result = HOST_BYTE(DID_ERROR); - do_scsi_done = ASC_TRUE; - scp_found = ASC_FALSE; - ret = SCSI_RESET_ERROR; - } else if ((boardp = ASC_BOARDP(shp))->flags & - (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { - ASC_PRINT2( -"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n", - boardp->id, boardp->flags); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_RESET_ERROR; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) - } else if (time_after_eq(jiffies, boardp->last_reset) && - time_before(jiffies, boardp->last_reset + (10 * HZ))) { -#else /* version < v2.1.0 */ - } else if (jiffies >= boardp->last_reset && - jiffies < (boardp->last_reset + (10 * HZ))) { -#endif /* version < v2.1.0 */ - /* - * Don't allow a reset to be attempted within 10 seconds - * of the last reset. - * - * If 'jiffies' wrapping occurs, the reset request will go - * through, because a wrapped 'jiffies' would not pass the - * test above. - */ - ASC_DBG(1, - "advansys_reset: reset within 10 sec of last reset ignored\n"); - do_scsi_done = ASC_TRUE; - if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || - (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } - scp->result = HOST_BYTE(DID_ERROR); - ret = SCSI_RESET_ERROR; - } else { - do_scsi_done = ASC_TRUE; - - /* Set reset flag to avoid nested reset or abort requests. */ - boardp->flags |= ASC_HOST_IN_RESET; + return FAILED; + } - /* - * If the request is on the target waiting or active queue - * or the board done queue, then remove it and note that it - * was found. - */ - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n"); - scp_found = ASC_TRUE; - } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { - ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n"); - scp_found = ASC_TRUE; - } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) { - scp_found = ASC_TRUE; - } else { - scp_found = ASC_FALSE; - } + boardp = ASC_BOARDP(shp); + ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n", + boardp->id); + /* + * Check for re-entrancy. + */ + spin_lock_irqsave(&boardp->lock, flags); + if (boardp->flags & ASC_HOST_IN_RESET) { + spin_unlock_irqrestore(&boardp->lock, flags); + return FAILED; + } + boardp->flags |= ASC_HOST_IN_RESET; + spin_unlock_irqrestore(&boardp->lock, flags); - if (ASC_NARROW_BOARD(boardp)) { - /* - * Narrow Board - * - * If the suggest reset bus flags are set, then reset the bus. - * Otherwise only reset the device. - */ - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (reset_flags & - (SCSI_RESET_SUGGEST_BUS_RESET | - SCSI_RESET_SUGGEST_HOST_RESET)) { -#endif /* version >= v1.3.89 */ + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level reset entrypoint. + */ + ASC_UNLOCK_IO_REQUEST_LOCK - /* - * Reset the target's SCSI bus. - */ - ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); - /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - /* cli(); XXX */ - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() failed\n"); - ret = SCSI_RESET_ERROR; - break; - } + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - } else { - /* - * Reset the specified device. If the device reset fails, - * then reset the SCSI bus. - */ + /* + * Reset the chip and SCSI bus. + */ + ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n"); + status = AscInitAsc1000Driver(asc_dvc_varp); - ASC_DBG1(1, - "advansys_reset: before AscResetDevice(), target %d\n", - scp->target); - /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */ - status = AscResetDevice(asc_dvc_varp, scp->target); - /* cli(); XXX */ - - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetDevice() success\n"); - device_reset = ASC_TRUE; - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, -"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); - /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - /* cli(); XXX */ - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); - ret = SCSI_RESET_ERROR; - break; - } - break; - } - } -#endif /* version >= v1.3.89 */ + /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */ + if (asc_dvc_varp->err_code) { + ASC_PRINT2( + "advansys_reset: board %d: SCSI bus reset error: 0x%x\n", + boardp->id, asc_dvc_varp->err_code); + ret = FAILED; + } else if (status) { + ASC_PRINT2( + "advansys_reset: board %d: SCSI bus reset warning: 0x%x\n", + boardp->id, status); } else { - /* - * Wide Board - * - * If the suggest reset bus flags are set, then reset the bus. - * Otherwise only reset the device. - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (reset_flags & - (SCSI_RESET_SUGGEST_BUS_RESET | - SCSI_RESET_SUGGEST_HOST_RESET)) { -#endif /* version >= v1.3.89 */ - - /* - * Reset the target's SCSI bus. - */ - ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n"); - switch (AdvResetChipAndSB(adv_dvc_varp)) { - case ASC_TRUE: - ASC_DBG(1, - "advansys_reset: AdvResetChipAndSB() success\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_FALSE: - default: - ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n"); - ret = SCSI_RESET_ERROR; - break; - } - /* - * Ensure all requests completed by the microcode have - * been processed by calling AdvISR(). - */ - (void) AdvISR(adv_dvc_varp); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - } else { - /* - * Reset the specified device. If the device reset fails, - * then reset the SCSI bus. - */ - - ASC_DBG1(1, - "advansys_reset: before AdvResetDevice(), target %d\n", - scp->target); - - switch (AdvResetDevice(adv_dvc_varp, scp->target)) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n"); - device_reset = ASC_TRUE; - ret = SCSI_RESET_SUCCESS; - break; - case ASC_FALSE: - default: - ASC_DBG(1, -"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n"); - - switch (AdvResetChipAndSB(adv_dvc_varp)) { - case ASC_TRUE: - ASC_DBG(1, - "advansys_reset: AdvResetChipAndSB() TRUE\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_FALSE: - default: - ASC_DBG(1, - "advansys_reset: AdvResetChipAndSB() ERROR\n"); - ret = SCSI_RESET_ERROR; - break; - } - break; - } - /* - * Ensure all requests completed by the microcode have - * been processed by calling AdvISR(). - */ - (void) AdvISR(adv_dvc_varp); - } -#endif /* version >= v1.3.89 */ + ASC_PRINT1( + "advansys_reset: board %d: SCSI bus reset successful.\n", + boardp->id); } + ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n"); + /* - * Because the ASC_HOST_IN_RESET flag causes both - * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'done' queue and - * prevents waiting commands from being executed, - * these queued requests must be handled here. + * Acquire the board lock. */ - done_scp = asc_dequeue_list(&boardp->done, &last_scp, - ASC_TID_ALL); + spin_lock_irqsave(&boardp->lock, flags); + } else { /* - * If a device reset was performed dequeue all waiting - * and active requests for the device and set the request - * status to DID_RESET. + * Wide Board * - * If a SCSI bus reset was performed dequeue all waiting - * and active requests for all devices and set the request - * status to DID_RESET. + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. */ - if (device_reset == ASC_TRUE) { - target = scp->target; - } else { - target = ASC_TID_ALL; - } + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; /* - * Add active requests to 'done_scp' and set the request status - * to DID_RESET. + * Reset the target's SCSI bus. */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->active, &last_scp, target); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active, - &new_last_scp, target); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } + ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n"); + switch (AdvResetChipAndSB(adv_dvc_varp)) { + case ASC_TRUE: + ASC_PRINT1("advansys_reset: board %d: SCSI bus reset successful.\n", + boardp->id); + break; + case ASC_FALSE: + default: + ASC_PRINT1("advansys_reset: board %d: SCSI bus reset error.\n", + boardp->id); + ret = FAILED; + break; } - /* - * Add waiting requests to 'done_scp' and set the request status - * to DID_RESET. + * Acquire the board lock and ensure all requests completed by the + * microcode have been processed by calling AdvISR(). */ - if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target); - for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - } else { - ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting, - &new_last_scp, target); - if (new_last_scp != NULL) { - ASC_ASSERT(REQPNEXT(last_scp) != NULL); - for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { - tscp->result = HOST_BYTE(DID_RESET); - } - last_scp = new_last_scp; - } - } + spin_lock_irqsave(&boardp->lock, flags); + (void) AdvISR(adv_dvc_varp); + } - /* Save the time of the most recently completed reset. */ - boardp->last_reset = jiffies; + /* Board lock is held. */ - /* Clear reset flag. */ - boardp->flags &= ~ASC_HOST_IN_RESET; + /* + * Dequeue all board 'done' requests. A pointer to the last request + * is returned in 'last_scp'. + */ + done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); - /* - * Start any waiting commands for the board. - */ - if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { - ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); - asc_execute_queue(&boardp->waiting); + /* + * Dequeue all board 'active' requests for all devices and set + * the request status to DID_RESET. A pointer to the last request + * is returned in 'last_scp'. + */ + if (done_scp == NULL) { + done_scp = asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL); + for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + } else { + /* Append to 'done_scp' at the end with 'last_scp'. */ + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active, + &new_last_scp, ASC_TID_ALL); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + last_scp = new_last_scp; } - ret = SCSI_RESET_SUCCESS; } - /* Interrupts could be enabled here. */ - - ASC_ASSERT(do_scsi_done != ASC_ERROR); - ASC_ASSERT(scp_found != ASC_ERROR); - if (do_scsi_done == ASC_TRUE) { - if (scp->scsi_done == NULL) { - ASC_PRINT1( -"advansys_reset: reset request scsi_done() is NULL, %lx\n", - (ulong) scp); - } else { - if (scp_found == ASC_FALSE) { - ASC_PRINT1( -"advansys_reset: reset request not active or waiting, completing anyway %lx\n", - (ulong) scp); + /* + * Dequeue all 'waiting' requests and set the request status + * to DID_RESET. + */ + if (done_scp == NULL) { + done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL); + for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); + } + } else { + /* Append to 'done_scp' at the end with 'last_scp'. */ + ASC_ASSERT(last_scp != NULL); + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting, + &new_last_scp, ASC_TID_ALL); + if (new_last_scp != NULL) { + ASC_ASSERT(REQPNEXT(last_scp) != NULL); + for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) { + tscp->result = HOST_BYTE(DID_RESET); } - ASC_STATS(scp->host, done); - scp->scsi_done(scp); + last_scp = new_last_scp; } } + /* Save the time of the most recently completed reset. */ + boardp->last_reset = jiffies; + + /* Clear reset flag. */ + boardp->flags &= ~ASC_HOST_IN_RESET; + + /* Release the board. */ + spin_unlock_irqrestore(&boardp->lock, flags); + /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until requests have been completed. + * Complete all the 'done_scp' requests. */ if (done_scp != NULL) { asc_scsi_done_list(done_scp); } - ASC_DBG1(1, "advansys_reset: ret %d\n", ret); + /* + * XXX - Remove this comment and the next line when SCSI mid-level + * no longer acquires 'io_request_lock' before calling the SCSI + * low-level reset entrypoint. + */ + ASC_LOCK_IO_REQUEST_LOCK - /* Re-enable interrupts, if they were enabled on entry. */ - restore_flags(flags); + ASC_DBG1(1, "advansys_reset: ret %d\n", ret); - ASC_ASSERT(ret != ASC_ERROR); return ret; } @@ -6671,11 +6192,7 @@ * ip[2]: cylinders */ int -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -advansys_biosparam(Disk *dp, int dep, int ip[]) -#else /* version >= v1.3.0 */ advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) -#endif /* version >= v1.3.0 */ { asc_board_t *boardp; @@ -6771,14 +6288,14 @@ #ifdef ADVANSYS_DEBUG ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]); for (i = 1; i < ints[0]; i++) { - ASC_DBG2(1, " ints[%d] %x", i, ints[i]); + ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]); } ASC_DBG(1, "\n"); #endif /* ADVANSYS_DEBUG */ for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) { asc_ioport[i-1] = ints[i]; - ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n", + ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%x\n", i - 1, asc_ioport[i-1]); } } @@ -6788,8 +6305,13 @@ * --- Loadable Driver Support */ -static Scsi_Host_Template driver_template = ADVANSYS; +#if ASC_LINUX_KERNEL24 +static +#endif +#if ASC_LINUX_KERNEL24 || (ASC_LINUX_KERNEL22 && defined(MODULE)) +Scsi_Host_Template driver_template = ADVANSYS; # include "scsi_module.c" +#endif /* @@ -6799,42 +6321,22 @@ /* * First-level interrupt handler. * - * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting - * adapter's asc_board_t. Because all boards are currently checked - * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id' - * could be used to identify an interrupt passed to the AdvanSys driver, - * which is for a device sharing an interrupt with an AdvanSys adapter. + * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because + * all boards are currently checked for interrupts on each interrupt, 'dev_id' + * is not referenced. 'dev_id' could be used to identify an interrupt passed + * to the AdvanSys driver which is for a device sharing an interrupt with + * an AdvanSys adapter. */ STATIC void -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) -advansys_interrupt(int irq, struct pt_regs *regs) -#else /* version >= v1.3.70 */ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs) -#endif /* version >= v1.3.70 */ { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ - unsigned long flags; -#endif /* version >= v2.1.95 */ + ulong flags; int i; asc_board_t *boardp; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *new_last_scp; - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags(flags); - cli(); -#else /* version >= v2.1.95 */ - /* - * Disable interrupts, if they aren't already disabled and acquire - * the I/O spinlock. - */ - spin_lock_irqsave(&io_request_lock, flags); -#endif /* version >= v2.1.95 */ - - ASC_DBG(1, "advansys_interrupt: begin\n"); + + ASC_DBG(1, "advansys_interrupt: begin\n"); /* * Check for interrupts on all boards. @@ -6842,8 +6344,9 @@ */ for (i = 0; i < asc_board_count; i++) { boardp = ASC_BOARDP(asc_host[i]); - ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n", - i, (ulong) boardp) + ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", + i, (ulong) boardp); + spin_lock_irqsave(&boardp->lock, flags); if (ASC_NARROW_BOARD(boardp)) { /* * Narrow Board @@ -6865,13 +6368,12 @@ /* * Start waiting requests and create a list of completed requests. - * - * If a reset or abort request is being performed for the board, - * the reset or abort handler will complete pending requests after - * it has completed. + * + * If a reset request is being performed for the board, the reset + * handler will complete pending requests after it has completed. */ - if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) { - ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n", + if ((boardp->flags & ASC_HOST_IN_RESET) == 0) { + ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n", (ulong) done_scp, (ulong) last_scp); /* Start any waiting commands for the board. */ @@ -6900,38 +6402,21 @@ } } } + spin_unlock_irqrestore(&boardp->lock, flags); } - /* Interrupts could be enabled here. */ - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here the - * original flags aren't restored until all requests have been - * completed. + * If interrupts were enabled on entry, then they + * are now enabled here. + * + * Complete all requests on the done list. */ asc_scsi_done_list(done_scp); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags(flags); -#else /* version >= v2.1.95 */ - /* - * Release the I/O spinlock and restore the original flags - * which will enable interrupts if and only if they were - * enabled on entry. - */ - spin_unlock_irqrestore(&io_request_lock, flags); -#endif /* version >= v2.1.95 */ - ASC_DBG(1, "advansys_interrupt: end\n"); return; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) /* * Set the number of commands to queue per device for the * specified host adapter. @@ -6960,22 +6445,11 @@ device->queue_depth = boardp->dvc_var.adv_dvc_var.max_dvc_qng; } - ASC_DBG3(1, "advansys_select_queue_depths: shp %lx, id %d, depth %d\n", + ASC_DBG3(1, + "advansys_select_queue_depths: shp 0x%lx, id %d, depth %d\n", (ulong) shp, device->id, device->queue_depth); } } -#endif /* version >= v1.3.89 */ - -/* - * Function used only with polled I/O requests that are initiated by - * advansys_command(). - */ -STATIC void -advansys_command_done(Scsi_Cmnd *scp) -{ - ASC_DBG1(1, "advansys_command_done: scp %lx\n", (ulong) scp); - scp->SCp.Status = 1; -} /* * Complete all requests on the singly linked list pointed @@ -6990,7 +6464,7 @@ ASC_DBG(2, "asc_scsi_done_list: begin\n"); while (scp != NULL) { - ASC_DBG1(3, "asc_scsi_done_list: scp %lx\n", (ulong) scp); + ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp); tscp = REQPNEXT(scp); REQPNEXT(scp) = NULL; ASC_STATS(scp->host, done); @@ -7038,12 +6512,15 @@ * scsi_done - used to save caller's done function * host_scribble - used for pointer to another Scsi_Cmnd * - * If this function returns ASC_NOERROR or ASC_ERROR the request - * has been enqueued on the board's 'done' queue and must be - * completed by the caller. + * If this function returns ASC_NOERROR the request has been enqueued + * on the board's 'active' queue and will be completed from the + * interrupt handler. + * + * If this function returns ASC_NOERROR the request has been enqueued + * on the board's 'done' queue and must be completed by the caller. * - * If ASC_BUSY is returned the request must be enqueued by the - * caller and re-tried later. + * If ASC_BUSY is returned the request will be enqueued by the + * caller on the target's waiting queue and re-tried later. */ STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *scp) @@ -7055,8 +6532,7 @@ Scsi_Device *device; int ret; - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n", + ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n", (ulong) scp, (ulong) scp->scsi_done); boardp = ASC_BOARDP(scp->host); @@ -7073,6 +6549,10 @@ * Build Asc Library request structure using the * global structures 'asc_scsi_req' and 'asc_sg_head'. * + * If an error is returned, then the request has been + * queued on the board done queue. It will be completed + * by the caller. + * * asc_build_req() can not return ASC_BUSY. */ if (asc_build_req(boardp, scp) == ASC_ERROR) { @@ -7092,18 +6572,20 @@ * request counter. Wrapping doesn't matter. */ boardp->reqcnt[scp->target]++; - asc_enqueue(&boardp->active, scp, ASC_BACK); ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); break; case ASC_BUSY: - /* Caller must enqueue request and retry later. */ + /* + * Caller will enqueue request on the target's waiting queue + * and retry later. + */ ASC_STATS(scp->host, exe_busy); break; case ASC_ERROR: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, exe_error); scp->result = HOST_BYTE(DID_ERROR); @@ -7111,7 +6593,7 @@ break; default: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, exe_unknown); scp->result = HOST_BYTE(DID_ERROR); @@ -7127,7 +6609,7 @@ /* * Build and get a pointer to an Adv Library request structure. * - * If the request is successfully built then send it below, + * If the request is successfully built then send it below, * otherwise return with an error. */ switch (adv_build_req(boardp, scp, &adv_scsiqp)) { @@ -7136,14 +6618,28 @@ break; case ASC_BUSY: ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n"); + /* + * If busy is returned the request has not been enqueued. + * It will be enqueued by the caller on the target's waiting + * queue and retried later. + * + * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg' + * count wide board busy conditions. They are updated in + * adv_build_req and adv_get_sglist, respectively. + */ return ASC_BUSY; case ASC_ERROR: + /* + * If an error is returned, then the request has been + * queued on the board done queue. It will be completed + * by the caller. + */ default: ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n"); ASC_STATS(scp->host, build_error); return ASC_ERROR; } - + /* * Execute the command. If there is no error, add the command * to the active queue. @@ -7161,12 +6657,15 @@ "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n"); break; case ASC_BUSY: - /* Caller must enqueue request and retry later. */ + /* + * Caller will enqueue request on the target's waiting queue + * and retry later. + */ ASC_STATS(scp->host, exe_busy); break; case ASC_ERROR: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n", boardp->id, adv_dvc_varp->err_code); ASC_STATS(scp->host, exe_error); scp->result = HOST_BYTE(DID_ERROR); @@ -7174,7 +6673,7 @@ break; default: ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n", +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n", boardp->id, adv_dvc_varp->err_code); ASC_STATS(scp->host, exe_unknown); scp->result = HOST_BYTE(DID_ERROR); @@ -7184,7 +6683,6 @@ } ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); return ret; } @@ -7194,7 +6692,8 @@ * The global structures 'asc_scsi_q' and 'asc_sg_head' are * used to build the request. * - * If an error occurs, then return ASC_ERROR. + * If an error occurs, then queue the request on the board done + * queue and return ASC_ERROR. */ STATIC int asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp) @@ -7212,21 +6711,24 @@ /* * Build the ASC_SCSI_Q request. + * + * For narrow boards a CDB length maximum of 12 bytes + * is supported. */ - ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); if (scp->cmd_len > ASC_MAX_CDB_LEN) { - scp->cmd_len = ASC_MAX_CDB_LEN; + ASC_PRINT3( +"asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n", + boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + return ASC_ERROR; } asc_scsi_q.cdbptr = &scp->cmnd[0]; asc_scsi_q.q2.cdb_len = scp->cmd_len; asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); asc_scsi_q.q1.target_lun = scp->lun; asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_scsi_q.q1.sense_addr = (ADV_PADDR) &scp->sense_buffer[0]; -#else /* version >= v2.0.0 */ asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); -#endif /* version >= v2.0.0 */ asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); /* @@ -7238,7 +6740,7 @@ * * The request count is incremented below for every successfully * started request. - * + * */ if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) && (boardp->reqcnt[scp->target] % 255) == 0) { @@ -7256,13 +6758,9 @@ * CDB request of single contiguous buffer. */ ASC_STATS(scp->host, cont_cnt); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_scsi_q.q1.data_addr = (ADV_PADDR) scp->request_buffer; -#else /* version >= v2.0.0 */ asc_scsi_q.q1.data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer)); -#endif /* version >= v2.0.0 */ - asc_scsi_q.q1.data_cnt = scp->request_bufflen; + asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen); ASC_STATS_ADD(scp->host, cont_xfer, ASC_CEILING(scp->request_bufflen, 512)); asc_scsi_q.q1.sg_queue_cnt = 0; @@ -7295,6 +6793,7 @@ asc_scsi_q.sg_head = &asc_sg_head; asc_scsi_q.q1.data_cnt = 0; asc_scsi_q.q1.data_addr = 0; + /* This is a byte value, otherwise it would need to be swapped. */ asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg; ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt); @@ -7303,12 +6802,8 @@ */ slp = (struct scatterlist *) scp->request_buffer; for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_sg_head.sg_list[sgcnt].addr = (ADV_PADDR) slp->address; -#else /* version >= v2.0.0 */ asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(virt_to_bus(slp->address)); -#endif /* version >= v2.0.0 */ asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } @@ -7354,9 +6849,9 @@ } /* - * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. + * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. */ - scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q); + scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q); /* * Initialize the structure. @@ -7379,24 +6874,31 @@ /* * Set CDB length and copy it to the request structure. + * For wide boards a CDB length maximum of 16 bytes + * is supported. */ - ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); - if (scp->cmd_len > ASC_MAX_CDB_LEN) { - scp->cmd_len = ASC_MAX_CDB_LEN; + if (scp->cmd_len > ADV_MAX_CDB_LEN) { + ASC_PRINT3( +"adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n", + boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + return ASC_ERROR; } scsiqp->cdb_len = scp->cmd_len; - for (i = 0; i < scp->cmd_len; i++) { + /* Copy first 12 CDB bytes to cdb[]. */ + for (i = 0; i < scp->cmd_len && i < 12; i++) { scsiqp->cdb[i] = scp->cmnd[i]; } + /* Copy last 4 CDB bytes, if present, to cdb16[]. */ + for (; i < scp->cmd_len; i++) { + scsiqp->cdb16[i - 12] = scp->cmnd[i]; + } scsiqp->target_id = scp->target; scsiqp->target_lun = scp->lun; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - scsiqp->sense_addr = (ADV_PADDR) &scp->sense_buffer[0]; -#else /* version >= v2.0.0 */ scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); -#endif /* version >= v2.0.0 */ scsiqp->sense_len = sizeof(scp->sense_buffer); /* @@ -7405,11 +6907,7 @@ */ scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen); scsiqp->vdata_addr = scp->request_buffer; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - scsiqp->data_addr = (ADV_PADDR) scp->request_buffer; -#else /* version >= v2.0.0 */ scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer)); -#endif /* version >= v2.0.0 */ if (scp->use_sg == 0) { /* @@ -7488,7 +6986,7 @@ ADV_PADDR sg_block_paddr; int i; - scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q); + scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q); slp = (struct scatterlist *) scp->request_buffer; sg_elem_cnt = scp->use_sg; prev_sg_block = NULL; @@ -7525,16 +7023,11 @@ sgblkp->next_sgblkp = NULL; /* - * Get 4 byte aligned virtual and physical addresses for + * Get 8 byte aligned virtual and physical addresses for * the allocated ADV_SG_BLOCK structure. */ - sg_block = (ADV_SG_BLOCK *) ADV_DWALIGN(&sgblkp->sg_block); - sg_block_paddr = -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - (ADV_PADDR) sg_block; -#else /* version >= v2.0.0 */ - virt_to_bus(sg_block); -#endif /* version >= v2.0.0 */ + sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block); + sg_block_paddr = virt_to_bus(sg_block); /* * Check if this is the first 'adv_sgblk_t' for the request. @@ -7568,11 +7061,7 @@ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { sg_block->sg_list[i].sg_addr = -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - (ADV_PADDR) slp->address; -#else /* version >= v2.0.0 */ cpu_to_le32(virt_to_bus(slp->address)); -#endif /* version >= v2.0.0 */ sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); @@ -7604,8 +7093,7 @@ struct Scsi_Host *shp; int i; - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n", + ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n", (ulong) asc_dvc_varp, (ulong) qdonep); ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); @@ -7614,7 +7102,7 @@ * command that has been completed. */ scp = (Scsi_Cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr); - ASC_DBG1(1, "asc_isr_callback: scp %lx\n", (ulong) scp); + ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong) scp); if (scp == NULL) { ASC_PRINT("asc_isr_callback: scp is NULL\n"); @@ -7634,24 +7122,24 @@ } if (i == asc_board_count) { ASC_PRINT2( - "asc_isr_callback: scp %lx has bad host pointer, host %lx\n", + "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n", (ulong) scp, (ulong) shp); return; } ASC_STATS(shp, callback); - ASC_DBG1(1, "asc_isr_callback: shp %lx\n", (ulong) shp); + ASC_DBG1(1, "asc_isr_callback: shp 0x%lx\n", (ulong) shp); /* * If the request isn't found on the active queue, it may - * have been removed to handle a reset or abort request. + * have been removed to handle a reset request. * Display a message and return. */ boardp = ASC_BOARDP(shp); ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var); if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { ASC_PRINT2( - "asc_isr_callback: board %d: scp %lx not on active queue\n", + "asc_isr_callback: board %d: scp 0x%lx not on active queue\n", boardp->id, (ulong) scp); return; } @@ -7675,20 +7163,20 @@ (ASC_SCSI_INQUIRY *) scp->request_buffer); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19) +#if ASC_LINUX_KERNEL24 /* * Check for an underrun condition. * * If there was no error and an underrun condition, then * then return the number of underrun bytes. */ - if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && + if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && qdonep->remain_bytes <= scp->request_bufflen != 0) { ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n", (unsigned) qdonep->remain_bytes); scp->resid = qdonep->remain_bytes; } -#endif /* version >= v2.3.19 */ +#endif break; case QD_WITH_ERROR: @@ -7710,15 +7198,15 @@ * byte as it is defined by SCSI. */ scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(qdonep->d3.scsi_stat); + STATUS_BYTE(qdonep->d3.scsi_stat); } else { - scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); + scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); } break; default: /* QHSTA error occurred */ - ASC_DBG1(1, "asc_isr_callback: host_stat %x\n", + ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n", qdonep->d3.host_stat); scp->result = HOST_BYTE(DID_BAD_TARGET); break; @@ -7732,7 +7220,7 @@ break; default: - ASC_DBG1(1, "asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat); + ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", qdonep->d3.done_stat); scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | STATUS_BYTE(qdonep->d3.scsi_stat); break; @@ -7749,7 +7237,7 @@ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); } - /* + /* * Because interrupts may be enabled by the 'Scsi_Cmnd' done * function, add the command to the end of the board's done queue. * The done function for the command will be called from @@ -7774,9 +7262,12 @@ Scsi_Cmnd *scp; struct Scsi_Host *shp; int i; +#if ASC_LINUX_KERNEL24 + ADV_DCNT resid_cnt; +#endif - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n", + + ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n", (ulong) adv_dvc_varp, (ulong) scsiqp); ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); @@ -7786,7 +7277,7 @@ * completed ADV_SCSI_REQ_Q structure. */ reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr); - ASC_DBG1(1, "adv_isr_callback: reqp %lx\n", (ulong) reqp); + ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong) reqp); if (reqp == NULL) { ASC_PRINT("adv_isr_callback: reqp is NULL\n"); return; @@ -7801,7 +7292,7 @@ * determined. */ scp = reqp->cmndp; - ASC_DBG1(1, "adv_isr_callback: scp %lx\n", (ulong) scp); + ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong) scp); if (scp == NULL) { ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); return; @@ -7824,18 +7315,17 @@ */ if (i == asc_board_count) { ASC_PRINT2( - "adv_isr_callback: scp %lx has bad host pointer, host %lx\n", + "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n", (ulong) scp, (ulong) shp); return; } ASC_STATS(shp, callback); - ASC_DBG1(1, "adv_isr_callback: shp %lx\n", (ulong) shp); + ASC_DBG1(1, "adv_isr_callback: shp 0x%lx\n", (ulong) shp); /* * If the request isn't found on the active queue, it may have been - * removed to handle a reset or abort request. Display a message and - * return. + * removed to handle a reset request. Display a message and return. * * Note: Because the structure may still be in use don't attempt * to free the adv_req_t and adv_sgblk_t, if any, structures. @@ -7844,7 +7334,7 @@ ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var); if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { ASC_PRINT2( - "adv_isr_callback: board %d: scp %lx not on active queue\n", + "adv_isr_callback: board %d: scp 0x%lx not on active queue\n", boardp->id, (ulong) scp); return; } @@ -7857,20 +7347,21 @@ ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n"); scp->result = 0; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19) +#if ASC_LINUX_KERNEL24 /* * Check for an underrun condition. * * If there was no error and an underrun condition, then * then return the number of underrun bytes. */ - if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0 && - scsiqp->data_cnt <= scp->request_bufflen) { + resid_cnt = le32_to_cpu(scsiqp->data_cnt); + if (scp->request_bufflen != 0 && resid_cnt != 0 && + resid_cnt <= scp->request_bufflen) { ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n", - (ulong) scsiqp->data_cnt); - scp->resid = scsiqp->data_cnt; + (ulong) resid_cnt); + scp->resid = resid_cnt; } -#endif /* version >= v2.3.19 */ +#endif break; case QD_WITH_ERROR: @@ -7900,7 +7391,7 @@ default: /* Some other QHSTA error occurred. */ - ASC_DBG1(1, "adv_isr_callback: host_status %x\n", + ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n", scsiqp->host_status); scp->result = HOST_BYTE(DID_BAD_TARGET); break; @@ -7913,7 +7404,7 @@ break; default: - ASC_DBG1(1, "adv_isr_callback: done_status %x\n", scsiqp->done_status); + ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", scsiqp->done_status); scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); break; } @@ -7929,7 +7420,7 @@ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); } - /* + /* * Because interrupts may be enabled by the 'Scsi_Cmnd' done * function, add the command to the end of the board's done queue. * The done function for the command will be called from @@ -8000,415 +7491,6 @@ } } -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI -/* - * Search for an AdvanSys PCI device in the PCI configuration space. - */ -ASC_INITFUNC( -STATIC int, -asc_srch_pci_dev(PCI_DEVICE *pciDevice) -) -{ - int ret = PCI_DEVICE_NOT_FOUND; - - ASC_DBG(2, "asc_srch_pci_dev: begin\n"); - - if (pci_scan_method == -1) { - pci_scan_method = asc_scan_method(); - } - pciDevice->type = pci_scan_method; - ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); - - ret = asc_pci_find_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret); - if (ret == PCI_DEVICE_FOUND) { - pciDevice->slotNumber = pciDevice->slotFound + 1; - pciDevice->startSlot = pciDevice->slotFound + 1; - } else { - if (pciDevice->bridge > pciDevice->busNumber) { - ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n", - pciDevice->bridge, pciDevice->busNumber); - pciDevice->busNumber++; - pciDevice->slotNumber = 0; - pciDevice->startSlot = 0; - pciDevice->endSlot = 0x0f; - ret = asc_srch_pci_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret); - } - } - - ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret); - return ret; -} - -/* - * Determine the access method to be used for 'pciDevice'. - */ -ASC_INITFUNC( -STATIC uchar, -asc_scan_method(void) -) -{ - ushort data; - PCI_DATA pciData; - uchar type; - uchar slot; - - ASC_DBG(2, "asc_scan_method: begin\n"); - memset(&pciData, 0, sizeof(pciData)); - for (type = 1; type < 3; type++) { - pciData.type = type; - for (slot = 0; slot < PCI_MAX_SLOT; slot++) { - pciData.slot = slot; - data = asc_get_cfg_word(&pciData); - if ((data != 0xFFFF) && (data != 0x0000)) { - ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type); - return (type); - } - } - } - ASC_DBG1(4, "asc_scan_method: type %d\n", type); - return (type); -} - -/* - * Check for an AdvanSys PCI device in 'pciDevice'. - * - * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND. - */ -ASC_INITFUNC( -STATIC int, -asc_pci_find_dev(PCI_DEVICE *pciDevice) -) -{ - PCI_DATA pciData; - ushort vendorid, deviceid; - uchar classcode, subclass; - uchar lslot; - - ASC_DBG(3, "asc_pci_find_dev: begin\n"); - pciData.type = pciDevice->type; - pciData.bus = pciDevice->busNumber; - pciData.func = pciDevice->devFunc; - lslot = pciDevice->startSlot; - for (; lslot < pciDevice->endSlot; lslot++) { - pciData.slot = lslot; - pciData.offset = VENDORID_OFFSET; - vendorid = asc_get_cfg_word(&pciData); - ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid); - if (vendorid != 0xffff) { - pciData.offset = DEVICEID_OFFSET; - deviceid = asc_get_cfg_word(&pciData); - ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid); - if ((vendorid == ASC_PCI_VENDORID) && - ((deviceid == ASC_PCI_DEVICE_ID_1100) || - (deviceid == ASC_PCI_DEVICE_ID_1200) || - (deviceid == ASC_PCI_DEVICE_ID_1300) || - (deviceid == ASC_PCI_DEVICE_ID_2300) || - (deviceid == ASC_PCI_DEVICE_ID_2500))) { - pciDevice->slotFound = lslot; - ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); - return PCI_DEVICE_FOUND; - } else { - pciData.offset = SUBCLASS_OFFSET; - subclass = asc_get_cfg_byte(&pciData); - pciData.offset = CLASSCODE_OFFSET; - classcode = asc_get_cfg_byte(&pciData); - if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) && - (subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) { - pciDevice->bridge++; - } - ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n", - subclass, classcode); - } - } - } - return PCI_DEVICE_NOT_FOUND; -} - -/* - * Read PCI configuration data into 'pciConfig'. - */ -ASC_INITFUNC( -STATIC void, -asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig) -) -{ - PCI_DATA pciData; - uchar counter; - uchar *localConfig; - - ASC_DBG1(4, "asc_get_pci_cfg: slotFound %d\n ", - pciDevice->slotFound); - - pciData.type = pciDevice->type; - pciData.bus = pciDevice->busNumber; - pciData.slot = pciDevice->slotFound; - pciData.func = pciDevice->devFunc; - localConfig = (uchar *) pciConfig; - - for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) { - pciData.offset = counter; - *localConfig = asc_get_cfg_byte(&pciData); - ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig); - localConfig++; - } - ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter); -} - -/* - * Read a word (16 bits) from the PCI configuration space. - * - * The configuration mechanism is checked for the correct access method. - */ -ASC_INITFUNC( -STATIC ushort, -asc_get_cfg_word(PCI_DATA *pciData) -) -{ - ushort tmp; - ADV_DCNT address; - ADV_DCNT lbus = pciData->bus; - ADV_DCNT lslot = pciData->slot; - ADV_DCNT lfunc = pciData->func; - uchar t2CFA, t2CF8; - ADV_DCNT t1CF8, t1CFC; - - ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %u, slot %u, func %u\n", - pciData->type, (unsigned) lbus, (unsigned) lslot, (unsigned) lfunc); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Read the configuration space type 2 locations. - */ - tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset)); - - outp(0xCFA, t2CFA); /* save PCI bus register */ - outp(0xCF8, t2CF8); /* save config space enable register */ - } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save the CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, - * func = <10:8>, reg = <7:2> - */ - address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); - - /* - * Write out the address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Read in word from CONFIG_DATA. - */ - tmp = (ushort) ((inpl(0xCFC) >> - ((pciData->offset & 2) * 8)) & 0xFFFF); - - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp); - return tmp; -} - -/* - * Reads a byte from the PCI configuration space. - * - * The configuration mechanism is checked for the correct access method. - */ -ASC_INITFUNC( -STATIC uchar, -asc_get_cfg_byte(PCI_DATA *pciData) -) -{ - uchar tmp; - ADV_DCNT address; - ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - ADV_DCNT t2CFA, t2CF8; - ADV_DCNT t1CF8, t1CFC; - - ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Read configuration space type 2 locations. - */ - tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); - - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ - } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); - - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Read in word from CONFIG_DATA. - */ - tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); - - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); - return tmp; -} - -/* - * Write a byte to the PCI configuration space. - */ -ASC_INITFUNC( -STATIC void, -asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) -) -{ - ADV_DCNT tmpl; - ADV_DCNT address; - ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - uchar t2CFA, t2CF8; - ADV_DCNT t1CF8, t1CFC; - - ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n", - pciData->type, byte_data); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write bus and enable registers. - */ - outp(0xCFA, pciData->bus); - - /* - * Set the function number. - */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Write the configuration space type 2 locations. - */ - outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data); - - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ - } else { - - /* - * Type 1 or 3 configuration mechanism. - * - * Save the CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | - (pciData->offset & 0xFC) | 0x80000000L); - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Write double word to CONFIG_DATA preserving the bytes - * in the double not written. - */ - tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8)); - outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8))); - - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG(4, "asc_put_cfg_byte: end\n"); -} -#endif /* ASC_CONFIG_PCI */ -#endif /* version < v2.1.93 */ - /* * Add a 'REQP' to the end of specified queue. Set 'tidmask' * to indicate a command is queued for the device. @@ -8422,9 +7504,8 @@ { int tid; - ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n", + ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n", (ulong) ascq, (ulong) reqp, flag); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); tid = REQPTID(reqp); @@ -8460,7 +7541,7 @@ } REQPTIME(reqp) = REQTIMESTAMP(); #endif /* ADVANSYS_STATS */ - ASC_DBG1(3, "asc_enqueue: reqp %lx\n", (ulong) reqp); + ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong) reqp); return; } @@ -8476,8 +7557,7 @@ { REQP reqp; - ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); + ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong) ascq, tid); ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if ((reqp = ascq->q_first[tid]) != NULL) { ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); @@ -8495,7 +7575,7 @@ REQTIMESTAT("asc_dequeue", ascq, reqp, tid); #endif /* ADVANSYS_STATS */ } - ASC_DBG1(3, "asc_dequeue: reqp %lx\n", (ulong) reqp); + ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong) reqp); return reqp; } @@ -8503,7 +7583,7 @@ * Return a pointer to a singly linked list of all the requests queued * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'. * - * If 'lastpp' is not NULL, '*lastpp' will be set to point to the + * If 'lastpp' is not NULL, '*lastpp' will be set to point to the * the last request returned in the singly linked list. * * 'tid' should either be a valid target id or if it is ASC_TID_ALL, @@ -8525,8 +7605,7 @@ REQP firstp, lastp; int i; - ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); + ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong) ascq, tid); ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); /* @@ -8586,7 +7665,7 @@ if (lastpp) { *lastpp = lastp; } - ASC_DBG1(3, "asc_dequeue_list: firstp %lx\n", (ulong) firstp); + ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong) firstp); return firstp; } @@ -8607,9 +7686,8 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n", + ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n", (ulong) ascq, (ulong) reqp); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); @@ -8660,37 +7738,7 @@ } ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); #endif /* ADVANSYS_STATS */ - ASC_DBG2(3, "asc_rmqueue: reqp %lx, ret %d\n", (ulong) reqp, ret); - return ret; -} - -/* - * If the specified 'REQP' is queued on the specified queue for - * the specified target device, return ASC_TRUE. - */ -STATIC int -asc_isqueued(asc_queue_t *ascq, REQP reqp) -{ - REQP treqp; - int tid; - int ret = ASC_FALSE; - - ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n", - (ulong) ascq, (ulong) reqp); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); - ASC_ASSERT(reqp != NULL); - - tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); - - for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) { - ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); - if (treqp == reqp) { - ret = ASC_TRUE; - break; - } - } - ASC_DBG1(3, "asc_isqueued: ret %x\n", ret); + ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong) reqp, ret); return ret; } @@ -8706,8 +7754,7 @@ REQP reqp; int i; - ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq); - ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); + ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong) ascq); /* * Execute queued commands for devices attached to * the current board in round-robin fashion. @@ -8721,7 +7768,10 @@ } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) == ASC_BUSY) { scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); - /* Put the request back at front of the list. */ + /* + * The request returned ASC_BUSY. Enqueue at the front of + * target's waiting list to maintain correct ordering. + */ asc_enqueue(ascq, reqp, ASC_FRONT); } } @@ -8730,7 +7780,7 @@ return; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +#ifdef CONFIG_PROC_FS /* * asc_prt_board_devices() * @@ -8810,7 +7860,7 @@ "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n"); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -"can be found at the AdvanSys FTP site: ftp://ftp.advansys.com/pub\n"); +"can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n"); ASC_PRT_NEXT(); } else { major = (boardp->bios_version >> 12) & 0xF; @@ -8829,10 +7879,10 @@ if (major < 3 || (major <= 3 && minor < 1) || (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) { len = asc_prt_line(cp, leftlen, -"Newer version of ROM BIOS is available at the AdvanSys FTP site:\n"); +"Newer version of ROM BIOS is available at the ConnectCom FTP site:\n"); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -"ftp://ftp.advansys.com/pub\n"); +"ftp://ftp.connectcom.net/pub\n"); ASC_PRT_NEXT(); } } @@ -8960,7 +8010,9 @@ int len; ASCEEP_CONFIG *ep; int i; +#ifdef CONFIG_ISA int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; +#endif /* CONFIG_ISA */ uchar serialstr[13]; boardp = ASC_BOARDP(shp); @@ -8992,11 +8044,11 @@ len = asc_prt_line(cp, leftlen, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng); + ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" cntl %x, no_scam %x\n", +" cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam); ASC_PRT_NEXT(); @@ -9054,12 +8106,14 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); +#ifdef CONFIG_ISA if (asc_dvc_varp->bus_type & ASC_IS_ISA) { len = asc_prt_line(cp, leftlen, " Host ISA DMA speed: %d MB/S\n", - isa_dma_speed[ep->isa_dma_speed]); + isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]); ASC_PRT_NEXT(); } +#endif /* CONFIG_ISA */ return totlen; } @@ -9088,6 +8142,7 @@ uchar serialstr[13]; ADVEEP_3550_CONFIG *ep_3550 = NULL; ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL; + ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL; ushort word; ushort *wordp; ushort sdtr_speed = 0; @@ -9097,9 +8152,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { ep_3550 = &boardp->eep_config.adv_3550_eep; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; + } else + { + ep_38C1600 = &boardp->eep_config.adv_38C1600_eep; } leftlen = cplen; @@ -9112,9 +8170,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { wordp = &ep_3550->serial_number_word1; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { wordp = &ep_38C0800->serial_number_word1; + } else + { + wordp = &ep_38C1600->serial_number_word1; } if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) { @@ -9133,20 +8194,30 @@ ep_3550->adapter_scsi_id, ep_3550->max_host_qng, ep_3550->max_dvc_qng); ASC_PRT_NEXT(); - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { len = asc_prt_line(cp, leftlen, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng, ep_38C0800->max_dvc_qng); ASC_PRT_NEXT(); - } - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) - { - word = ep_3550->termination; } else { + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng, + ep_38C1600->max_dvc_qng); + ASC_PRT_NEXT(); + } + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) + { + word = ep_3550->termination; + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + { word = ep_38C0800->termination_lvd; + } else + { + word = ep_38C1600->termination_lvd; } switch (word) { case 1: @@ -9167,15 +8238,21 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { len = asc_prt_line(cp, leftlen, -" termination: %u (%s), bios_ctrl: %x\n", +" termination: %u (%s), bios_ctrl: 0x%x\n", ep_3550->termination, termstr, ep_3550->bios_ctrl); ASC_PRT_NEXT(); - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { len = asc_prt_line(cp, leftlen, -" termination: %u (%s), bios_ctrl: %x\n", +" termination: %u (%s), bios_ctrl: 0x%x\n", ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl); ASC_PRT_NEXT(); + } else + { + len = asc_prt_line(cp, leftlen, +" termination: %u (%s), bios_ctrl: 0x%x\n", + ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl); + ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, @@ -9191,9 +8268,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->disc_enable; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->disc_enable; + } else + { + word = ep_38C1600->disc_enable; } len = asc_prt_line(cp, leftlen, " Disconnects: "); @@ -9209,9 +8289,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->tagqng_able; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->tagqng_able; + } else + { + word = ep_38C1600->tagqng_able; } len = asc_prt_line(cp, leftlen, " Command Queuing: "); @@ -9227,9 +8310,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->start_motor; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->start_motor; + } else + { + word = ep_38C1600->start_motor; } len = asc_prt_line(cp, leftlen, " Start Motor: "); @@ -9273,9 +8359,12 @@ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->wdtr_able; - } else + } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { word = ep_38C0800->wdtr_able; + } else + { + word = ep_38C1600->wdtr_able; } len = asc_prt_line(cp, leftlen, " Wide Transfer: "); @@ -9288,7 +8377,8 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) + if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 || + adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) { len = asc_prt_line(cp, leftlen, " Synchronous Transfer Speed (Mhz):\n "); @@ -9352,9 +8442,7 @@ int totlen; int len; int chip_scsi_id; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) int i; -#endif /* version >= v1.3.89 */ boardp = ASC_BOARDP(shp); @@ -9367,39 +8455,31 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) -" host_busy %u, last_reset %u, max_id %u, max_lun %u\n", - shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun); -#else /* version >= v1.3.89 */ " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n", shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun, shp->max_channel); -#endif /* version >= v1.3.89 */ ASC_PRT_NEXT(); - + len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) -" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", - shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); -#else /* version >= v1.3.57 */ " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); -#endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) -" unchecked_isa_dma %d, loaded_as_module %d\n", - shp->unchecked_isa_dma, shp->loaded_as_module); -#else /* version >= v1.3.57 */ " unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n", shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module); -#endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n", - boardp->flags, boardp->last_reset, jiffies); + len = asc_prt_line(cp, leftlen, +" flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n", + boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port); + ASC_PRT_NEXT(); + + /* 'shp->n_io_port' may be truncated because it is only one byte. */ + len = asc_prt_line(cp, leftlen, +" io_port 0x%x, n_io_port 0x%x\n", + shp->io_port, shp->n_io_port); ASC_PRT_NEXT(); if (ASC_NARROW_BOARD(boardp)) { @@ -9408,7 +8488,6 @@ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) { len = asc_prt_line(cp, leftlen, " queue_depth:"); ASC_PRT_NEXT(); @@ -9427,7 +8506,6 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } -#endif /* version >= v1.3.89 */ return totlen; } @@ -9470,12 +8548,12 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" chip_version %u, lib_version %x, lib_serial_no %u, mcode_date %x\n", +" chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n", c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" mcode_version %x, err_code %u\n", +" mcode_version 0x%x, err_code %u\n", c->mcode_version, v->err_code); ASC_PRT_NEXT(); @@ -9663,14 +8741,14 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" iop_base %lx, cable_detect: %X, err_code %u\n", +" iop_base 0x%lx, cable_detect: %X, err_code %u\n", v->iop_base, AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT, v->err_code); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n", +" chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n", c->chip_version, c->lib_version, c->mcode_date, c->mcode_version); ASC_PRT_NEXT(); @@ -9862,7 +8940,7 @@ } /* - * asc_proc_copy() + * asc_proc_copy() * * Copy proc information to a read buffer taking into account the current * read offset in the file and the remaining space in the read buffer. @@ -9872,13 +8950,13 @@ char *cp, int cplen) { int cnt = 0; - + ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", (unsigned) offset, (unsigned) advoffset, cplen); if (offset <= advoffset) { /* Read offset below current offset, copy everything. */ cnt = ASC_MIN(cplen, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n", + ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n", (ulong) curbuf, (ulong) cp, cnt); memcpy(curbuf, cp, cnt); } else if (offset < advoffset + cplen) { @@ -9886,7 +8964,7 @@ cnt = (advoffset + cplen) - offset; cp = (cp + cplen) - cnt; cnt = ASC_MIN(cnt, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n", + ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n", (ulong) curbuf, (ulong) cp, cnt); memcpy(curbuf, cp, cnt); } @@ -9924,7 +9002,7 @@ va_end(args); return ret; } -#endif /* version >= v1.3.0 */ +#endif /* CONFIG_PROC_FS */ /* @@ -9940,56 +9018,33 @@ STATIC void DvcSleepMilliSecond(ADV_DCNT n) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) - ADV_DCNT i; -#endif /* version < v2.1.0 */ - ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n); -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) mdelay(n); -#else /* version < v2.1.0 */ - for (i = 0; i < n; i++) { - udelay(1000); - } -#endif /* version < v2.1.0 */ } -STATIC int +/* + * Currently and inline noop but leave as a placeholder. + * Leave DvcEnterCritical() as a noop placeholder. + */ +STATIC inline ulong DvcEnterCritical(void) { - int flags; - - save_flags(flags); - cli(); - return flags; + return 0; } -STATIC void -DvcLeaveCritical(int flags) +/* + * Critical sections are all protected by the board spinlock. + * Leave DvcLeaveCritical() as a noop placeholder. + */ +STATIC inline void +DvcLeaveCritical(ulong flags) { - restore_flags(flags); -} - -STATIC ADV_DCNT -DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ADV_DCNT buf_len, - ASC_SG_HEAD *asc_sg_head_ptr) -{ - ADV_DCNT buf_size; - - buf_size = buf_len; - asc_sg_head_ptr->entry_cnt = 1; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - asc_sg_head_ptr->sg_list[0].addr = (ADV_PADDR) buf_addr; -#else /* version >= v2.0.0 */ - asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr); -#endif /* version >= v2.0.0 */ - asc_sg_head_ptr->sg_list[0].bytes = buf_size; - return buf_size; + return; } /* * void - * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) + * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) * * Calling/Exit State: * none @@ -9998,23 +9053,24 @@ * Output an ASC_SCSI_Q structure to the chip */ STATIC void -DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words) +DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) { int i; - ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words); + ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words); AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++, outbuf++) { - if (i == 2 || i == 10) { + for (i = 0; i < 2 * words; i += 2) { + if (i == 4 || i == 20) { continue; } - AscSetChipLramDataNoSwap(iop_base, *outbuf); + outpw(iop_base + IOP_RAM_DATA, + ((ushort) outbuf[i + 1] << 8) | outbuf[i]); } } /* * void - * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) + * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) * * Calling/Exit State: * none @@ -10023,79 +9079,21 @@ * Input an ASC_QDONE_INFO structure from the chip */ STATIC void -DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words) +DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) { int i; + ushort word; AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++, inbuf++) { - if (i == 5) { + for (i = 0; i < 2 * words; i += 2) { + if (i == 10) { continue; } - *inbuf = AscGetChipLramDataNoSwap(iop_base); - } - ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words); -} - -/* - * void DvcOutPortWords(ushort iop_base, ushort &outbuf, int words) - * - * Calling/Exit State: - * none - * - * Description: - * output a buffer to an i/o port address - */ -STATIC void -DvcOutPortWords(ushort iop_base, ushort *outbuf, int words) -{ - int i; - - for (i = 0; i < words; i++, outbuf++) - outpw(iop_base, *outbuf); -} - -/* - * void DvcInPortWords(ushort iop_base, ushort &outbuf, int words) - * - * Calling/Exit State: - * none - * - * Description: - * input a buffer from an i/o port address - */ -STATIC void -DvcInPortWords(ushort iop_base, ushort *inbuf, int words) -{ - int i; - - for (i = 0; i < words; i++, inbuf++) - *inbuf = inpw(iop_base); -} - -/* - * void DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords) - * - * Calling/Exit State: - * none - * - * Description: - * output a buffer of 32-bit integers to an i/o port address in - * 16 bit integer units - */ -STATIC void -DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords) -{ - int i; - int words; - ushort *pw; - - pw = (ushort *) pdw; - words = dwords << 1; - for(i = 0; i < words; i++, pw++) { - outpw(port, *pw); + word = inpw(iop_base + IOP_RAM_DATA); + inbuf[i] = word & 0xff; + inbuf[i + 1] = (word >> 8) & 0xff; } - return; + ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words); } /* @@ -10104,24 +9102,10 @@ ASC_INITFUNC( STATIC uchar, DvcReadPCIConfigByte( - ASC_DVC_VAR *asc_dvc, + ASC_DVC_VAR *asc_dvc, ushort offset) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - return asc_get_cfg_byte(&pciData); -#else /* ASC_CONFIG_PCI */ - return 0; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI uchar byte_data; pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), @@ -10129,10 +9113,9 @@ ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, &byte_data); return byte_data; -#else /* CONFIG_PCI */ +#else /* !defined(CONFIG_PCI) */ return 0; -#endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ +#endif /* !defined(CONFIG_PCI) */ } /* @@ -10141,30 +9124,17 @@ ASC_INITFUNC( STATIC void, DvcWritePCIConfigByte( - ASC_DVC_VAR *asc_dvc, - ushort offset, + ASC_DVC_VAR *asc_dvc, + ushort offset, uchar byte_data) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - asc_put_cfg_byte(&pciData, byte_data); -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info), ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, byte_data); #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -10192,6 +9162,7 @@ return(0); } +#ifdef CONFIG_ISA if((bus_type & ASC_IS_EISA) != 0) { cfg_lsw = AscGetEisaChipCfg(iop_base); @@ -10200,6 +9171,7 @@ (cfg_lsw * ASC_BIOS_BANK_SIZE)); return(bios_addr); }/* if */ +#endif /* CONFIG_ISA */ cfg_lsw = AscGetChipCfgLsw(iop_base); @@ -10238,14 +9210,10 @@ { ADV_PADDR paddr; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) - paddr = (ADV_PADDR) vaddr; -#else /* version >= v2.0.0 */ paddr = virt_to_bus(vaddr); -#endif /* version >= v2.0.0 */ ASC_DBG4(4, - "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", + "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr); return paddr; @@ -10257,24 +9225,10 @@ ASC_INITFUNC( STATIC uchar, DvcAdvReadPCIConfigByte( - ADV_DVC_VAR *asc_dvc, + ADV_DVC_VAR *asc_dvc, ushort offset) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - return asc_get_cfg_byte(&pciData); -#else /* ASC_CONFIG_PCI */ - return 0; -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI uchar byte_data; pcibios_read_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), @@ -10285,7 +9239,6 @@ #else /* CONFIG_PCI */ return 0; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -10294,30 +9247,19 @@ ASC_INITFUNC( STATIC void, DvcAdvWritePCIConfigByte( - ADV_DVC_VAR *asc_dvc, - ushort offset, + ADV_DVC_VAR *asc_dvc, + ushort offset, uchar byte_data) ) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93) -#ifdef ASC_CONFIG_PCI - PCI_DATA pciData; - - pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); - pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); - pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); - pciData.offset = offset; - pciData.type = pci_scan_method; - asc_put_cfg_byte(&pciData, byte_data); -#endif /* ASC_CONFIG_PCI */ -#else /* version >= v2.1.93 */ #ifdef CONFIG_PCI pcibios_write_config_byte(ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info), PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info), ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, byte_data); +#else /* CONFIG_PCI */ + return 0; #endif /* CONFIG_PCI */ -#endif /* version >= v2.1.93 */ } /* @@ -10325,6 +9267,7 @@ */ #ifdef ADVANSYS_STATS +#ifdef CONFIG_PROC_FS /* * asc_prt_board_stats() * @@ -10341,11 +9284,7 @@ int totlen; int len; struct asc_stats *s; - int i; - ushort chip_scsi_id; asc_board_t *boardp; - asc_queue_t *active; - asc_queue_t *waiting; leftlen = cplen; totlen = len = 0; @@ -10356,15 +9295,16 @@ len = asc_prt_line(cp, leftlen, "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); - + len = asc_prt_line(cp, leftlen, -" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n", - s->command, s->queuecommand, s->abort, s->reset, s->biosparam); +" queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n", + s->queuecommand, s->reset, s->biosparam, s->interrupt); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" interrupt %lu, callback %lu, done %lu\n", - s->interrupt, s->callback, s->done); +" callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n", + s->callback, s->done, s->build_error, s->adv_build_noreq, + s->adv_build_nosg); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, @@ -10372,17 +9312,6 @@ s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown); ASC_PRT_NEXT(); - if (ASC_NARROW_BOARD(boardp)) { - len = asc_prt_line(cp, leftlen, -" build_error %lu\n", - s->build_error); - } else { - len = asc_prt_line(cp, leftlen, -" build_error %lu, build_noreq %lu, build_nosg %lu\n", - s->build_error, s->adv_build_noreq, s->adv_build_nosg); - } - ASC_PRT_NEXT(); - /* * Display data transfer statistics. */ @@ -10437,6 +9366,40 @@ " Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ); ASC_PRT_NEXT(); + + return totlen; +} + +/* + * asc_prt_target_stats() + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * This is separated from asc_prt_board_stats because a full set + * of targets will overflow ASC_PRTBUF_SIZE. + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen) +{ + int leftlen; + int totlen; + int len; + struct asc_stats *s; + ushort chip_scsi_id; + asc_board_t *boardp; + asc_queue_t *active; + asc_queue_t *waiting; + + leftlen = cplen; + totlen = len = 0; + + boardp = ASC_BOARDP(shp); + s = &boardp->asc_stats; + active = &ASC_BOARDP(shp)->active; waiting = &ASC_BOARDP(shp)->waiting; @@ -10446,70 +9409,77 @@ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; } - for (i = 0; i <= ADV_MAX_TID; i++) { - - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } + if ((chip_scsi_id == tgt_id) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) { + return 0; + } - if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) { - len = asc_prt_line(cp, leftlen, " target %d\n", i); + do { + if (active->q_tot_cnt[tgt_id] > 0 || waiting->q_tot_cnt[tgt_id] > 0) { + len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", - active->q_cur_cnt[i], active->q_max_cnt[i], - active->q_tot_cnt[i], - active->q_min_tim[i], active->q_max_tim[i], - (active->q_tot_cnt[i] == 0) ? 0 : - (active->q_tot_tim[i]/active->q_tot_cnt[i]), - (active->q_tot_cnt[i] == 0) ? 0 : - ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i])); - ASC_PRT_NEXT(); + active->q_cur_cnt[tgt_id], active->q_max_cnt[tgt_id], + active->q_tot_cnt[tgt_id], + active->q_min_tim[tgt_id], active->q_max_tim[tgt_id], + (active->q_tot_cnt[tgt_id] == 0) ? 0 : + (active->q_tot_tim[tgt_id]/active->q_tot_cnt[tgt_id]), + (active->q_tot_cnt[tgt_id] == 0) ? 0 : + ASC_TENTHS(active->q_tot_tim[tgt_id], + active->q_tot_cnt[tgt_id])); + ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, + len = asc_prt_line(cp, leftlen, " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n", - waiting->q_cur_cnt[i], waiting->q_max_cnt[i], - waiting->q_tot_cnt[i], - waiting->q_min_tim[i], waiting->q_max_tim[i], - (waiting->q_tot_cnt[i] == 0) ? 0 : - (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]), - (waiting->q_tot_cnt[i] == 0) ? 0 : - ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i])); - ASC_PRT_NEXT(); + waiting->q_cur_cnt[tgt_id], waiting->q_max_cnt[tgt_id], + waiting->q_tot_cnt[tgt_id], + waiting->q_min_tim[tgt_id], waiting->q_max_tim[tgt_id], + (waiting->q_tot_cnt[tgt_id] == 0) ? 0 : + (waiting->q_tot_tim[tgt_id]/waiting->q_tot_cnt[tgt_id]), + (waiting->q_tot_cnt[tgt_id] == 0) ? 0 : + ASC_TENTHS(waiting->q_tot_tim[tgt_id], + waiting->q_tot_cnt[tgt_id])); + ASC_PRT_NEXT(); } - } + } while (0); return totlen; } +#endif /* CONFIG_PROC_FS */ #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG /* * asc_prt_scsi_host() */ -STATIC void +STATIC void asc_prt_scsi_host(struct Scsi_Host *s) { asc_board_t *boardp; boardp = ASC_BOARDP(s); - printk("Scsi_Host at addr %lx\n", (ulong) s); + printk("Scsi_Host at addr 0x%lx\n", (ulong) s); printk( -" next %lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", +" next 0x%lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", (ulong) s->next, s->extra_bytes, s->host_busy, s->host_no, (unsigned) s->last_reset); +#if ASC_LINUX_KERNEL24 + printk( +" host_queue 0x%lx, hostt 0x%lx\n", + (ulong) s->host_queue, (ulong) s->hostt); +#elif ASC_LINUX_KERNEL22 printk( -" host_queue %lx, hostt %lx, block %lx,\n", +" host_queue 0x%lx, hostt 0x%lx, block 0x%lx,\n", (ulong) s->host_queue, (ulong) s->hostt, (ulong) s->block); +#endif printk( -" base %lu, io_port %lu, n_io_port %u, irq %d,\n", - (ulong) s->base, (ulong) s->io_port, s->n_io_port, - s->irq); +" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n", + (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq); printk( " dma_channel %d, this_id %d, can_queue %d,\n", @@ -10532,49 +9502,49 @@ /* * asc_prt_scsi_cmnd() */ -STATIC void +STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *s) { - printk("Scsi_Cmnd at addr %lx\n", (ulong) s); + printk("Scsi_Cmnd at addr 0x%lx\n", (ulong) s); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) printk( -" host %x, device %x, target %u, lun %u\n", - (unsigned) s->host, (unsigned) s->device, s->target, s->lun); -#else /* version >= v1.3.0 */ - printk( -" host %lx, device %lx, target %u, lun %u, channel %u,\n", +" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n", (ulong) s->host, (ulong) s->device, s->target, s->lun, s->channel); -#endif /* version >= v1.3.0 */ asc_prt_hex(" CDB", s->cmnd, s->cmd_len); +#if ASC_LINUX_KERNEL24 + printk ( +"sc_data_direction %u, resid %d\n", + s->sc_data_direction, s->resid); +#endif + printk( -" use_sg %u, sglist_len %u, abort_reason %x\n", +" use_sg %u, sglist_len %u, abort_reason 0x%x\n", s->use_sg, s->sglist_len, s->abort_reason); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) - printk( -" retries %d, allowed %d\n", - s->retries, s->allowed); -#else /* version >= v1.3.89 */ printk( -" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n", +" serial_number 0x%x, serial_number_at_timeout 0x%x, retries %d, allowed %d\n", (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout, s->retries, s->allowed); -#endif /* version >= v1.3.89 */ printk( " timeout_per_command %d, timeout_total %d, timeout %d\n", s->timeout_per_command, s->timeout_total, s->timeout); +#if ASC_LINUX_KERNEL24 + printk( +" internal_timeout %u, flags %u\n", + s->internal_timeout, s->flags); +#elif ASC_LINUX_KERNEL22 printk( " internal_timeout %u, flags %u, this_count %d\n", - s->internal_timeout, s->flags, s->this_count); + s->internal_timeout, s->flags,s->this_count); +#endif printk( -" scsi_done %lx, done %lx, host_scribble %lx, result %x\n", +" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", (ulong) s->scsi_done, (ulong) s->done, (ulong) s->host_scribble, s->result); @@ -10586,57 +9556,59 @@ /* * asc_prt_asc_dvc_var() */ -STATIC void +STATIC void asc_prt_asc_dvc_var(ASC_DVC_VAR *h) { - printk("ASC_DVC_VAR at addr %lx\n", (ulong) h); + printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong) h); printk( -" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n", +" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); printk( -" bus_type %d, isr_callback %lx, exe_callback %lx, init_sdtr %x,\n", +" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n", h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback, (unsigned) h->init_sdtr); printk( -" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n", +" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n", (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng, (unsigned) h->unit_not_ready, (unsigned) h->chip_no); - + printk( -" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n", +" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n", (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor, - (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); + (unsigned) h->scsi_reset_wait); printk( -" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n", +" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n", (unsigned) h->is_in_int, (unsigned) h->max_total_qng, (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt); printk( -" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n", +" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n", (unsigned) h->last_q_shortage, (unsigned) h->init_state, (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer); printk( -" cfg %lx\n", - (ulong) h->cfg); +" cfg 0x%lx, irq_no 0x%x\n", + (ulong) h->cfg, (unsigned) h->irq_no); } /* * asc_prt_asc_dvc_cfg() */ -STATIC void +STATIC void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) { - printk("ASC_DVC_CFG at addr %lx\n", (ulong) h); + printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong) h); printk( -" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, sdtr_enable %x,\n", - h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, - h->sdtr_enable); +" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n", + h->can_tagged_qng, h->cmd_qng_enabled); + printk( +" disc_enable 0x%x, sdtr_enable 0x%x,\n", + h->disc_enable, h->sdtr_enable); printk( " chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n", @@ -10644,48 +9616,49 @@ h->chip_version); printk( -" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n", +" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n", h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date); printk( -" mcode_version %d, overrun_buf %lx\n", +" mcode_version %d, overrun_buf 0x%lx\n", h->mcode_version, (ulong) h->overrun_buf); } /* * asc_prt_asc_scsi_q() */ -STATIC void +STATIC void asc_prt_asc_scsi_q(ASC_SCSI_Q *q) { ASC_SG_HEAD *sgp; int i; - printk("ASC_SCSI_Q at addr %lx\n", (ulong) q); + printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong) q); printk( -" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n", +" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n", q->q2.target_ix, q->q1.target_lun, - (unsigned) q->q2.srb_ptr, q->q2.tag_code); + (ulong) q->q2.srb_ptr, q->q2.tag_code); printk( -" data_addr %lx, data_cnt %lu, sense_addr %lx, sense_len %u,\n", - (ulong) q->q1.data_addr, (ulong) q->q1.data_cnt, - (ulong) q->q1.sense_addr, q->q1.sense_len); +" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", + (ulong) le32_to_cpu(q->q1.data_addr), + (ulong) le32_to_cpu(q->q1.data_cnt), + (ulong) le32_to_cpu(q->q1.sense_addr), q->q1.sense_len); printk( -" cdbptr %lx, cdb_len %u, sg_head %lx, sg_queue_cnt %u\n", +" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n", (ulong) q->cdbptr, q->q2.cdb_len, (ulong) q->sg_head, q->q1.sg_queue_cnt); if (q->sg_head) { sgp = q->sg_head; - printk("ASC_SG_HEAD at addr %lx\n", (ulong) sgp); + printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong) sgp); printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt); for (i = 0; i < sgp->entry_cnt; i++) { - printk(" [%u]: addr %lx, bytes %lu\n", - i, (ulong) sgp->sg_list[i].addr, - (ulong) sgp->sg_list[i].bytes); + printk(" [%u]: addr 0x%lx, bytes %lu\n", + i, (ulong) le32_to_cpu(sgp->sg_list[i].addr), + (ulong) le32_to_cpu(sgp->sg_list[i].bytes)); } } @@ -10694,17 +9667,17 @@ /* * asc_prt_asc_qdone_info() */ -STATIC void +STATIC void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) { - printk("ASC_QDONE_INFO at addr %lx\n", (ulong) q); + printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong) q); printk( -" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n", - (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, - q->d2.tag_code, q->d3.done_stat); +" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n", + (ulong) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, + q->d2.tag_code); printk( -" host_stat %x, scsi_stat %x, scsi_msg %x\n", - q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); +" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n", + q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); } /* @@ -10712,7 +9685,7 @@ * * Display an ADV_DVC_VAR structure. */ -STATIC void +STATIC void asc_prt_adv_dvc_var(ADV_DVC_VAR *h) { printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h); @@ -10723,8 +9696,8 @@ printk( " isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n", - (ulong) h->isr_callback, (unsigned) h->wdtr_able, - (unsigned) h->sdtr_able); + (ulong) h->isr_callback, (unsigned) h->sdtr_able, + (unsigned) h->wdtr_able); printk( " start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n", @@ -10732,12 +9705,12 @@ (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); printk( -" max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n", +" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n", (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng, (ulong) h->carr_freelist); printk( -" icq_sp %lx, irq_sp %lx\n", +" icq_sp 0x%lx, irq_sp 0x%lx\n", (ulong) h->icq_sp, (ulong) h->irq_sp); printk( @@ -10745,7 +9718,7 @@ (unsigned) h->no_scam, (unsigned) h->tagqng_able); printk( -" chip_scsi_id 0x%x, cfg %lx\n", +" chip_scsi_id 0x%x, cfg 0x%lx\n", (unsigned) h->chip_scsi_id, (ulong) h->cfg); } @@ -10754,7 +9727,7 @@ * * Display an ADV_DVC_CFG structure. */ -STATIC void +STATIC void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) { printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h); @@ -10768,7 +9741,7 @@ h->chip_version, h->mcode_date); printk( -" mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n", +" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n", h->mcode_version, h->pci_device_id, h->lib_version); printk( @@ -10781,37 +9754,38 @@ * * Display an ADV_SCSI_REQ_Q structure. */ -STATIC void +STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) { int sg_blk_cnt; struct asc_sg_block *sg_ptr; - printk("ADV_SCSI_REQ_Q at addr %lx\n", (ulong) q); + printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong) q); printk( " target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag); printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", - q->cntl, (ulong) q->data_addr, (ulong) q->vdata_addr); + q->cntl, (ulong) le32_to_cpu(q->data_addr), (ulong) q->vdata_addr); printk( " data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", - (ulong) q->data_cnt, (ulong) q->sense_addr, q->sense_len); + (ulong) le32_to_cpu(q->data_cnt), + (ulong) le32_to_cpu(q->sense_addr), q->sense_len); printk( " cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", q->cdb_len, q->done_status, q->host_status, q->scsi_status); printk( -" sg_working_ix %x, sg_working_data_cnt %lx, target_cmd %u\n", - q->sg_working_ix, (ulong) q->sg_working_data_cnt, q->target_cmd); +" sg_working_ix 0x%x, target_cmd %u\n", + q->sg_working_ix, q->target_cmd); printk( -" scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n", - (ulong) q->scsiq_rptr, (ulong) q->sg_real_addr, - (ulong) q->sg_list_ptr); +" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n", + (ulong) le32_to_cpu(q->scsiq_rptr), + (ulong) le32_to_cpu(q->sg_real_addr), (ulong) q->sg_list_ptr); /* Display the request's ADV_SG_BLOCK structures. */ if (q->sg_list_ptr != NULL) @@ -10846,17 +9820,17 @@ { int i; - printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n", + printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n", (ulong) b, sgblockno); - printk(" sg_cnt %u, sg_ptr %lx\n", - b->sg_cnt, (ulong) b->sg_ptr); + printk(" sg_cnt %u, sg_ptr 0x%lx\n", + b->sg_cnt, (ulong) le32_to_cpu(b->sg_ptr)); ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK); if (b->sg_ptr != 0) { ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK); } for (i = 0; i < b->sg_cnt; i++) { - printk(" [%u]: sg_addr %lx, sg_count %lx\n", + printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n", i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count); } } @@ -10864,10 +9838,10 @@ /* * asc_prt_hex() * - * Print hexadecimal output in 4 byte groupings 32 bytes + * Print hexadecimal output in 4 byte groupings 32 bytes * or 8 double-words per line. */ -STATIC void +STATIC void asc_prt_hex(char *f, uchar *s, int l) { int i; @@ -10878,7 +9852,7 @@ printk("%s: (%d bytes)\n", f, l); for (i = 0; i < l; i += 32) { - + /* Display a maximum of 8 double-words per line. */ if ((k = (l - i) / 4) >= 8) { k = 8; @@ -10919,27 +9893,6 @@ } #endif /* ADVANSYS_DEBUG */ -#ifdef ADVANSYS_ASSERT -/* - * advansys_interrupts_enabled() - * - * Return 1 if interrupts are enabled, otherwise return 0. - */ -STATIC int -advansys_interrupts_enabled(void) -{ - int flags; - - save_flags(flags); - if (flags & 0x0200) { - return ASC_TRUE; - } else { - return ASC_FALSE; - } -} -#endif /* ADVANSYS_ASSERT */ - - /* * --- Asc Library Functions */ @@ -11047,42 +10000,47 @@ return (0); } -ASC_INITFUNC( -STATIC ASC_DCNT, +STATIC ASC_DCNT AscLoadMicroCode( PortAddr iop_base, ushort s_addr, - ushort *mcode_buf, + uchar *mcode_buf, ushort mcode_size ) -) { ASC_DCNT chksum; ushort mcode_word_size; ushort mcode_chksum; + /* Write the microcode buffer starting at LRAM address 0. */ mcode_word_size = (ushort) (mcode_size >> 1); AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); - AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size); + chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); + ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong) chksum); mcode_chksum = (ushort) AscMemSumLramWord(iop_base, - (ushort) ASC_CODE_SEC_BEG, + (ushort) ASC_CODE_SEC_BEG, (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2)); + ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n", + (ulong) mcode_chksum); AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); return (chksum); } -ASC_INITFUNC( -STATIC int, +STATIC int AscFindSignature( PortAddr iop_base ) -) { ushort sig_word; + ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n", + iop_base, AscGetChipSignatureByte(iop_base)); if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { + ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n", + iop_base, AscGetChipSignatureWord(iop_base)); sig_word = AscGetChipSignatureWord(iop_base); if ((sig_word == (ushort) ASC_1000_ID0W) || (sig_word == (ushort) ASC_1000_ID0W_FIX)) { @@ -11092,13 +10050,15 @@ return (0); } -STATIC uchar _isa_pnp_inited ASC_INITDATA = 0; STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA = { 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8 }; +#ifdef CONFIG_ISA +STATIC uchar _isa_pnp_inited ASC_INITDATA = 0; + ASC_INITFUNC( STATIC PortAddr, AscSearchIOPortAddr( @@ -11155,11 +10115,11 @@ iop_base = _asc_def_iop_base[i]; if (check_region(iop_base, ASC_IOADR_GAP) != 0) { ASC_DBG1(1, - "AscSearchIOPortAddr11: check_region() failed I/O port %x\n", + "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n", iop_base); continue; } - ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base); + ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base); if (AscFindSignature(iop_base)) { return (iop_base); } @@ -11169,24 +10129,25 @@ ASC_INITFUNC( STATIC void, -AscToggleIRQAct( - PortAddr iop_base -) +AscSetISAPNPWaitForKey( + void) ) { - AscSetChipStatus(iop_base, CIW_IRQ_ACT); - AscSetChipStatus(iop_base, 0); + outp(ASC_ISA_PNP_PORT_ADDR, 0x02); + outp(ASC_ISA_PNP_PORT_WRITE, 0x02); return; } +#endif /* CONFIG_ISA */ ASC_INITFUNC( STATIC void, -AscSetISAPNPWaitForKey( - void) +AscToggleIRQAct( + PortAddr iop_base +) ) { - outp(ASC_ISA_PNP_PORT_ADDR, 0x02); - outp(ASC_ISA_PNP_PORT_WRITE, 0x02); + AscSetChipStatus(iop_base, CIW_IRQ_ACT); + AscSetChipStatus(iop_base, 0); return; } @@ -11267,6 +10228,7 @@ return (0); } +#ifdef CONFIG_ISA ASC_INITFUNC( STATIC void, AscEnableIsaDma( @@ -11283,8 +10245,9 @@ } return; } +#endif /* CONFIG_ISA */ -STATIC int +STATIC int AscIsrChipHalted( ASC_DVC_VAR *asc_dvc ) @@ -11343,10 +10306,10 @@ return (0); } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { - AscMemWordCopyFromLram(iop_base, + AscMemWordCopyPtrFromLram(iop_base, ASCV_MSGIN_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &ext_msg, + sizeof(EXT_MSG) >> 1); if (ext_msg.msg_type == MS_EXTEND && ext_msg.msg_req == MS_SDTR_CODE && @@ -11420,10 +10383,10 @@ ext_msg.msg_len == MS_WDTR_LEN) { ext_msg.wdtr_width = 0; - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &ext_msg, + sizeof(EXT_MSG) >> 1); q_cntl |= QC_MSG_OUT; AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -11433,10 +10396,10 @@ } else { ext_msg.msg_type = M1_MSG_REJECT; - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & ext_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &ext_msg, + sizeof(EXT_MSG) >> 1); q_cntl |= QC_MSG_OUT; AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -11496,10 +10459,10 @@ return (0); } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { - AscMemWordCopyFromLram(iop_base, + AscMemWordCopyPtrFromLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & out_msg, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &out_msg, + sizeof(EXT_MSG) >> 1); if ((out_msg.msg_type == MS_EXTEND) && (out_msg.msg_len == MS_SDTR_LEN) && @@ -11554,7 +10517,9 @@ } AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); - } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) + } +#if CC_VERY_LONG_SG_LIST + else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) { uchar q_no; ushort q_addr; @@ -11678,16 +10643,15 @@ } scsi_sg_q.q_no = next_qp; - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG), - (ushort *) &scsi_sg_q, - (ushort) (sizeof(ASC_SG_LIST_Q) >> 1)); - - AscMemDWordCopyToLram( iop_base, - (ushort) (q_addr+ASC_SGQ_LIST_BEG ), - (ADV_PADDR *) - &sg_head->sg_list[scsiq->next_sg_index], - (ushort) sg_list_dwords); + AscMemWordCopyPtrToLram(iop_base, + q_addr + ASC_SCSIQ_SGHD_CPY_BEG, + (uchar *) &scsi_sg_q, + sizeof(ASC_SG_LIST_Q) >> 1); + + AscMemDWordCopyPtrToLram(iop_base, + q_addr + ASC_SGQ_LIST_BEG, + (uchar *) &sg_head->sg_list[scsiq->next_sg_index], + sg_list_dwords); scsiq->next_sg_index += ASC_SG_LIST_PER_Q; @@ -11713,6 +10677,7 @@ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return(0); } +#endif /* CC_VERY_LONG_SG_LIST */ return (0); } @@ -11728,9 +10693,10 @@ uchar sg_queue_cnt; DvcGetQinfo(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG), - (ushort *) scsiq, - (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2)); + q_addr + ASC_SCSIQ_DONE_INFO_BEG, + (uchar *) scsiq, + (sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2); + _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); scsiq->q_status = (uchar) _val; @@ -11994,7 +10960,8 @@ return (int_pending); } -STATIC uchar _asc_mcode_buf[] ASC_INITDATA = +/* Microcode buffer is kept after initialization for error recovery. */ +STATIC uchar _asc_mcode_buf[] = { 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -12142,8 +11109,8 @@ 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84, }; -STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf); -STATIC ADV_DCNT _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL; +STATIC ushort _asc_mcode_size = sizeof(_asc_mcode_buf); +STATIC ADV_DCNT _asc_mcode_chksum = 0x012C453FUL; #define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = @@ -12173,7 +11140,7 @@ ) { PortAddr iop_base; - int last_int_level; + ulong last_int_level; int sta; int n_q_required; int disable_syn_offset_one_fix; @@ -12235,6 +11202,8 @@ #if !CC_VERY_LONG_SG_LIST if (sg_entry_cnt > ASC_MAX_SG_LIST) { + asc_dvc->in_critical_cnt--; + DvcLeaveCritical(last_int_level); return(ERR); } #endif /* !CC_VERY_LONG_SG_LIST */ @@ -12252,10 +11221,10 @@ if (scsiq->q1.cntl & QC_SG_HEAD) { data_cnt = 0; for (i = 0; i < sg_entry_cnt; i++) { - data_cnt += (ADV_DCNT) sg_head->sg_list[i].bytes; + data_cnt += (ADV_DCNT) le32_to_cpu(sg_head->sg_list[i].bytes); } } else { - data_cnt = scsiq->q1.data_cnt; + data_cnt = le32_to_cpu(scsiq->q1.data_cnt); } if (data_cnt != 0UL) { if (data_cnt < 512UL) { @@ -12279,7 +11248,7 @@ scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | ASC_TAG_FLAG_DISABLE_DISCONNECT); } else { - scsiq->q2.tag_code &= 0x23; + scsiq->q2.tag_code &= 0x27; } if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { if (asc_dvc->bug_fix_cntl) { @@ -12287,23 +11256,27 @@ if ((scsi_cmd == SCSICMD_Read6) || (scsi_cmd == SCSICMD_Read10)) { addr = - (ADV_PADDR) - sg_head->sg_list[sg_entry_cnt_minus_one].addr + - (ADV_DCNT) - sg_head->sg_list[sg_entry_cnt_minus_one].bytes; + (ADV_PADDR) le32_to_cpu( + sg_head->sg_list[sg_entry_cnt_minus_one].addr) + + (ADV_DCNT) le32_to_cpu( + sg_head->sg_list[sg_entry_cnt_minus_one].bytes); extra_bytes = (uchar) ((ushort) addr & 0x0003); if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) { scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; scsiq->q1.extra_bytes = extra_bytes; - sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= - (ASC_DCNT) extra_bytes; + data_cnt = le32_to_cpu( + sg_head->sg_list[sg_entry_cnt_minus_one].bytes); + data_cnt -= (ASC_DCNT) extra_bytes; + sg_head->sg_list[sg_entry_cnt_minus_one].bytes = + cpu_to_le32(data_cnt); } } } } sg_head->entry_to_copy = sg_head->entry_cnt; +#if CC_VERY_LONG_SG_LIST /* * Set the sg_entry_cnt to the maximum possible. The rest of * the SG elements will be copied when the RISC completes the @@ -12313,6 +11286,7 @@ { sg_entry_cnt = ASC_MAX_SG_LIST; } +#endif /* CC_VERY_LONG_SG_LIST */ n_q_required = AscSgListToQueue(sg_entry_cnt); if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) { @@ -12331,14 +11305,17 @@ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { if ((scsi_cmd == SCSICMD_Read6) || (scsi_cmd == SCSICMD_Read10)) { - addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; + addr = le32_to_cpu(scsiq->q1.data_addr) + + le32_to_cpu(scsiq->q1.data_cnt); extra_bytes = (uchar) ((ushort) addr & 0x0003); if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) { - if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) { + data_cnt = le32_to_cpu(scsiq->q1.data_cnt); + if (((ushort) data_cnt & 0x01FF) == 0) { scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; - scsiq->q1.data_cnt -= (ASC_DCNT) extra_bytes; + data_cnt -= (ASC_DCNT) extra_bytes; + scsiq->q1.data_cnt = cpu_to_le32(data_cnt); scsiq->q1.extra_bytes = extra_bytes; } } @@ -12501,14 +11478,15 @@ scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; } scsiq->q1.status = QS_FREE; - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), - (ushort *) scsiq->cdbptr, - (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); + AscMemWordCopyPtrToLram(iop_base, + q_addr + ASC_SCSIQ_CDB_BEG, + (uchar *) scsiq->cdbptr, + scsiq->q2.cdb_len >> 1); + DvcPutScsiQ(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), - (ushort *) & scsiq->q1.cntl, - (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))); + q_addr + ASC_SCSIQ_CPY_BEG, + (uchar *) &scsiq->q1.cntl, + ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1); AscWriteLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); @@ -12541,6 +11519,7 @@ saved_data_cnt = scsiq->q1.data_cnt; scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr; scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes; +#if CC_VERY_LONG_SG_LIST /* * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST * then not all SG elements will fit in the allocated queues. @@ -12551,10 +11530,10 @@ { /* * Set sg_entry_cnt to be the number of SG elements that - * will fit in the allocated SG queues. It is minus 1 because - * first SG element handled above. ASC_MAX_SG_LIST is already - * inflated by 1 to account for this. For example it may - * be 50 which is 1 + 7 queues * 7 SG elements. + * will fit in the allocated SG queues. It is minus 1, because + * the first SG element is handled above. ASC_MAX_SG_LIST is + * already inflated by 1 to account for this. For example it + * may be 50 which is 1 + 7 queues * 7 SG elements. */ sg_entry_cnt = ASC_MAX_SG_LIST - 1; @@ -12565,13 +11544,16 @@ scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST; } else { +#endif /* CC_VERY_LONG_SG_LIST */ /* * Set sg_entry_cnt to be the number of SG elements that - * will fit in the allocated SG queues. Refer to comment - * above regarding why it is - 1. + * will fit in the allocated SG queues. It is minus 1, because + * the first SG element is handled above. */ sg_entry_cnt = sg_head->entry_cnt - 1; +#if CC_VERY_LONG_SG_LIST } +#endif /* CC_VERY_LONG_SG_LIST */ if (sg_entry_cnt != 0) { scsiq->q1.cntl |= QC_SG_HEAD; q_addr = ASC_QNO_TO_QADDR(q_no); @@ -12592,6 +11574,7 @@ scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; } } else { +#if CC_VERY_LONG_SG_LIST /* * This is the last SG queue in the list of * allocated SG queues. If there are more @@ -12603,8 +11586,11 @@ scsi_sg_q.cntl |= QCSG_SG_XFER_MORE; } else { +#endif /* CC_VERY_LONG_SG_LIST */ scsi_sg_q.cntl |= QCSG_SG_XFER_END; +#if CC_VERY_LONG_SG_LIST } +#endif /* CC_VERY_LONG_SG_LIST */ sg_list_dwords = sg_entry_cnt << 1; if (i == 0) { scsi_sg_q.sg_list_cnt = sg_entry_cnt; @@ -12619,14 +11605,14 @@ (ushort) (q_addr + ASC_SCSIQ_B_FWD)); scsi_sg_q.q_no = next_qp; q_addr = ASC_QNO_TO_QADDR(next_qp); - AscMemWordCopyToLram(iop_base, - (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG), - (ushort *) & scsi_sg_q, - (ushort) (sizeof (ASC_SG_LIST_Q) >> 1)); - AscMemDWordCopyToLram(iop_base, - (ushort) (q_addr + ASC_SGQ_LIST_BEG), - (ADV_PADDR *) &sg_head->sg_list[sg_index], - (ushort) sg_list_dwords); + AscMemWordCopyPtrToLram(iop_base, + q_addr + ASC_SCSIQ_SGHD_CPY_BEG, + (uchar *) &scsi_sg_q, + sizeof(ASC_SG_LIST_Q) >> 1); + AscMemDWordCopyPtrToLram(iop_base, + q_addr + ASC_SGQ_LIST_BEG, + (uchar *) &sg_head->sg_list[sg_index], + sg_list_dwords); sg_index += ASC_SG_LIST_PER_Q; scsiq->next_sg_index = sg_index; } @@ -12640,171 +11626,30 @@ } STATIC int -AscAbortSRB( - ASC_DVC_VAR *asc_dvc, - ADV_VADDR srb_ptr +AscSetRunChipSynRegAtID( + PortAddr iop_base, + uchar tid_no, + uchar sdtr_data ) { - int sta; - ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; - PortAddr iop_base; + int sta = FALSE; - iop_base = asc_dvc->iop_base; - sta = ERR; - saved_unit_not_ready = asc_dvc->unit_not_ready; - asc_dvc->unit_not_ready = 0xFF; - AscWaitISRDone(asc_dvc); - if (AscStopQueueExe(iop_base) == 1) { - if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) { - sta = 1; - AscCleanUpBusyQueue(iop_base); - AscStartQueueExe(iop_base); - } else { - sta = 0; - AscStartQueueExe(iop_base); - } + if (AscHostReqRiscHalt(iop_base)) { + sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscStartChip(iop_base); + return (sta); } - asc_dvc->unit_not_ready = saved_unit_not_ready; return (sta); } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) STATIC int -AscResetDevice( - ASC_DVC_VAR *asc_dvc, - uchar target_ix +AscSetChipSynRegAtID( + PortAddr iop_base, + uchar id, + uchar sdtr_data ) { - PortAddr iop_base; - int sta; - uchar tid_no; - - ASC_SCSI_BIT_ID_TYPE target_id; - int i; - ASC_SCSI_REQ_Q scsiq_buf; - ASC_SCSI_REQ_Q *scsiq; - uchar *buf; - ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; - iop_base = asc_dvc->iop_base; - tid_no = ASC_TIX_TO_TID(target_ix); - target_id = ASC_TID_TO_TARGET_ID(tid_no); - saved_unit_not_ready = asc_dvc->unit_not_ready; - asc_dvc->unit_not_ready = target_id; - sta = ERR; - AscWaitTixISRDone(asc_dvc, target_ix); - if (AscStopQueueExe(iop_base) == 1) { - if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) { - AscCleanUpBusyQueue(iop_base); - AscStartQueueExe(iop_base); - AscWaitTixISRDone(asc_dvc, target_ix); - sta = TRUE; - scsiq = (ASC_SCSI_REQ_Q *) & scsiq_buf; - buf = (uchar *) & scsiq_buf; - for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) { - *buf++ = 0x00; - } - scsiq->r1.status = (uchar) QS_READY; - scsiq->r2.cdb_len = 6; - scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE; - scsiq->r1.target_id = target_id; - scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0); - scsiq->cdbptr = (uchar *) scsiq->cdb; - scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT; - AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG, - M1_BUS_DVC_RESET); - asc_dvc->unit_not_ready &= ~target_id; - asc_dvc->sdtr_done |= target_id; - if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q *) scsiq) - == 1) { - asc_dvc->unit_not_ready = target_id; - DvcSleepMilliSecond(1000); - _AscWaitQDone(iop_base, (ASC_SCSI_Q *) scsiq); - if (AscStopQueueExe(iop_base) == 1) { - AscCleanUpDiscQueue(iop_base); - AscStartQueueExe(iop_base); - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetRunChipSynRegAtID(iop_base, tid_no, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); - } - AscWaitTixISRDone(asc_dvc, target_ix); - } - } else { - sta = 0; - } - asc_dvc->sdtr_done &= ~target_id; - } else { - sta = ERR; - AscStartQueueExe(iop_base); - } - } - asc_dvc->unit_not_ready = saved_unit_not_ready; - return (sta); -} -#endif /* version >= v1.3.89 */ - -STATIC int -AscResetSB( - ASC_DVC_VAR *asc_dvc -) -{ - int sta; - int i; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - asc_dvc->unit_not_ready = 0xFF; - sta = TRUE; - AscWaitISRDone(asc_dvc); - AscStopQueueExe(iop_base); - asc_dvc->sdtr_done = 0; - AscResetChipAndScsiBus(asc_dvc); - DvcSleepMilliSecond((ASC_DCNT) ((ushort) asc_dvc->scsi_reset_wait * 1000)); - AscReInitLram(asc_dvc); - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cur_dvc_qng[i] = 0; - if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) { - AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB); - } - } - asc_dvc->err_code = 0; - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - sta = ERR; - } - if (AscStartChip(iop_base) == 0) { - sta = ERR; - } - AscStartQueueExe(iop_base); - asc_dvc->unit_not_ready = 0; - asc_dvc->queue_full_or_busy = 0; - return (sta); -} - -STATIC int -AscSetRunChipSynRegAtID( - PortAddr iop_base, - uchar tid_no, - uchar sdtr_data -) -{ - int sta = FALSE; - - if (AscHostReqRiscHalt(iop_base)) { - sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscStartChip(iop_base); - return (sta); - } - return (sta); -} - -STATIC int -AscSetChipSynRegAtID( - PortAddr iop_base, - uchar id, - uchar sdtr_data -) -{ - ASC_SCSI_BIT_ID_TYPE org_id; + ASC_SCSI_BIT_ID_TYPE org_id; int i; int sta = TRUE; @@ -12831,16 +11676,6 @@ return (sta); } -STATIC int -AscReInitLram( - ASC_DVC_VAR *asc_dvc -) -{ - AscInitLram(asc_dvc); - AscInitQLinkVar(asc_dvc); - return (0); -} - STATIC ushort AscInitLram( ASC_DVC_VAR *asc_dvc @@ -12942,31 +11777,7 @@ } -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -_AscWaitQDone( - PortAddr iop_base, - ASC_SCSI_Q * scsiq -) -{ - ushort q_addr; - uchar q_status; - int count = 0; - - while (scsiq->q1.q_no == 0); - q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); - do { - q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); - DvcSleepMilliSecond(100L); - if (count++ > 30) { - return (0); - } - } while ((q_status & QS_READY) != 0); - return (1); -} -#endif /* version >= v1.3.89 */ - -STATIC uchar +STATIC uchar AscMsgOutSDTR( ASC_DVC_VAR *asc_dvc, uchar sdtr_period, @@ -12987,18 +11798,18 @@ if ((sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <= asc_dvc->max_sdtr_index) { - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & sdtr_buf, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &sdtr_buf, + sizeof (EXT_MSG) >> 1); return ((sdtr_period_index << 4) | sdtr_offset); } else { sdtr_buf.req_ack_offset = 0; - AscMemWordCopyToLram(iop_base, + AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort *) & sdtr_buf, - (ushort) (sizeof (EXT_MSG) >> 1)); + (uchar *) &sdtr_buf, + sizeof (EXT_MSG) >> 1); return (0); } } @@ -13101,95 +11912,6 @@ } STATIC int -AscRiscHaltedAbortSRB( - ASC_DVC_VAR *asc_dvc, - ASC_VADDR srb_ptr -) -{ - PortAddr iop_base; - ushort q_addr; - uchar q_no; - ASC_QDONE_INFO scsiq_buf; - ASC_QDONE_INFO *scsiq; - ASC_ISR_CALLBACK asc_isr_callback; - int last_int_level; - - iop_base = asc_dvc->iop_base; - asc_isr_callback = asc_dvc->isr_callback; - last_int_level = DvcEnterCritical(); - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; - q_no++) { - q_addr = ASC_QNO_TO_QADDR(q_no); - scsiq->d2.srb_ptr = AscReadLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR)); - if (scsiq->d2.srb_ptr == srb_ptr) { - _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) - && ((scsiq->q_status & QS_ABORTED) == 0) - && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - scsiq->q_status |= QS_ABORTED; - scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - 0L); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - scsiq->q_status); - (*asc_isr_callback) (asc_dvc, scsiq); - return (1); - } - } - } - DvcLeaveCritical(last_int_level); - return (0); -} - -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscRiscHaltedAbortTIX( - ASC_DVC_VAR *asc_dvc, - uchar target_ix -) -{ - PortAddr iop_base; - ushort q_addr; - uchar q_no; - ASC_QDONE_INFO scsiq_buf; - ASC_QDONE_INFO *scsiq; - ASC_ISR_CALLBACK asc_isr_callback; - int last_int_level; - - iop_base = asc_dvc->iop_base; - asc_isr_callback = asc_dvc->isr_callback; - last_int_level = DvcEnterCritical(); - scsiq = (ASC_QDONE_INFO *) & scsiq_buf; - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; - q_no++) { - q_addr = ASC_QNO_TO_QADDR(q_no); - _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) && - ((scsiq->q_status & QS_ABORTED) == 0) && - ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - if (scsiq->d2.target_ix == target_ix) { - scsiq->q_status |= QS_ABORTED; - scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - 0L); - AscWriteLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), - scsiq->q_status); - (*asc_isr_callback) (asc_dvc, scsiq); - } - } - } - DvcLeaveCritical(last_int_level); - return (1); -} -#endif /* version >= v1.3.89 */ - -STATIC int AscHostReqRiscHalt( PortAddr iop_base ) @@ -13237,119 +11959,6 @@ return (0); } -STATIC int -AscStartQueueExe( - PortAddr iop_base -) -{ - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); - } - return (1); -} - -STATIC int -AscCleanUpBusyQueue( - PortAddr iop_base -) -{ - int count; - uchar stop_code; - - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_CLEAN_UP_BUSY_Q); - do { - stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0) - break; - DvcSleepMilliSecond(100); - } while (count++ < 20); - } - return (1); -} - -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) -STATIC int -AscCleanUpDiscQueue( - PortAddr iop_base -) -{ - int count; - uchar stop_code; - - count = 0; - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_CLEAN_UP_DISC_Q); - do { - stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0) - break; - DvcSleepMilliSecond(100); - } while (count++ < 20); - } - return (1); -} -#endif /* version >= v1.3.89 */ - -STATIC int -AscWaitTixISRDone( - ASC_DVC_VAR *asc_dvc, - uchar target_ix -) -{ - uchar cur_req; - uchar tid_no; - int i = 0; - - tid_no = ASC_TIX_TO_TID(target_ix); - while (i++ < 10) { - if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { - break; - } - DvcSleepMilliSecond(1000L); - if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { - break; - } - } - return (1); -} - -STATIC int -AscWaitISRDone( - ASC_DVC_VAR *asc_dvc -) -{ - int tid; - - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); - } - return (1); -} - -STATIC ASC_PADDR -AscGetOnePhyAddr( - ASC_DVC_VAR *asc_dvc, - uchar * buf_addr, - ASC_DCNT buf_size -) -{ - ASC_MIN_SG_HEAD sg_head; - - sg_head.entry_cnt = ASC_MIN_SG_LIST; - if (DvcGetSGList(asc_dvc, (uchar *) buf_addr, - buf_size, (ASC_SG_HEAD *) &sg_head) != buf_size) { - return (0L); - } - if (sg_head.entry_cnt > 1) { - return (0L); - } - return ((ASC_PADDR) sg_head.sg_list[0].addr); -} - STATIC void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec) { @@ -13362,6 +11971,7 @@ udelay((nano_sec + 999)/1000); } +#ifdef CONFIG_ISA ASC_INITFUNC( STATIC ASC_DCNT, AscGetEisaProductID( @@ -13420,6 +12030,7 @@ } return (0); } +#endif /* CONFIG_ISA */ STATIC int AscStartChip( @@ -13593,6 +12204,7 @@ return (ASC_MAX_PCI_DMA_COUNT); } +#ifdef CONFIG_ISA ASC_INITFUNC( STATIC ushort, AscGetIsaDmaChannel( @@ -13664,6 +12276,7 @@ AscSetBank(iop_base, 0); return (speed_value); } +#endif /* CONFIG_ISA */ ASC_INITFUNC( STATIC ushort, @@ -13841,19 +12454,19 @@ asc_dvc->cfg->chip_scsi_id) { asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; } +#ifdef CONFIG_ISA if (asc_dvc->bus_type & ASC_IS_ISA) { AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); } +#endif /* CONFIG_ISA */ return (warn_code); } -ASC_INITFUNC( -STATIC ushort, +STATIC ushort AscInitAsc1000Driver( ASC_DVC_VAR *asc_dvc ) -) { ushort warn_code; PortAddr iop_base; @@ -13877,7 +12490,9 @@ warn_code |= AscInitLram(asc_dvc); if (asc_dvc->err_code != 0) return (UW_ERR); - if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf, + ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n", + (ulong) _asc_mcode_chksum); + if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf, _asc_mcode_size) != _asc_mcode_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return (warn_code); @@ -13912,7 +12527,7 @@ asc_dvc->bug_fix_cntl = 0; asc_dvc->pci_fix_asyn_xfer = 0; asc_dvc->pci_fix_asyn_xfer_always = 0; - asc_dvc->init_state = 0; + /* asc_dvc->init_state initalized in AscInitGetConfig(). */ asc_dvc->sdtr_done = 0; asc_dvc->cur_total_qng = 0; asc_dvc->is_in_int = 0; @@ -13988,9 +12603,11 @@ AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); asc_dvc->bus_type = ASC_IS_ISAPNP; } +#ifdef CONFIG_ISA if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); } +#endif /* CONFIG_ISA */ for (i = 0; i <= ASC_MAX_TID; i++) { asc_dvc->cur_dvc_qng[i] = 0; asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; @@ -14037,7 +12654,7 @@ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; return (warn_code); } - eep_config = (ASCEEP_CONFIG *) & eep_config_buf; + eep_config = (ASCEEP_CONFIG *) &eep_config_buf; cfg_msw = AscGetChipCfgMsw(iop_base); cfg_lsw = AscGetChipCfgLsw(iop_base); if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { @@ -14046,6 +12663,7 @@ AscSetChipCfgMsw(iop_base, cfg_msw); } chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum); if (chksum == 0) { chksum = 0xaa55; } @@ -14064,10 +12682,14 @@ } eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; + ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n", + eep_config->chksum); if (chksum != eep_config->chksum) { if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == ASC_CHIP_VER_PCI_ULTRA_3050 ) { + ASC_DBG(1, +"AscInitFromEEP: chksum error ignored; EEPROM-less board\n"); eep_config->init_sdtr = 0xFF; eep_config->disc_enable = 0xFF; eep_config->start_motor = 0xFF; @@ -14075,7 +12697,7 @@ eep_config->max_total_qng = 0xF0; eep_config->max_tag_qng = 0x20; eep_config->cntl = 0xBFFF; - eep_config->chip_scsi_id = 7; + ASC_EEP_SET_CHIP_ID(eep_config, 7); eep_config->no_scam = 0; eep_config->adapter_info[0] = 0; eep_config->adapter_info[1] = 0; @@ -14085,6 +12707,8 @@ /* Indicate EEPROM-less board. */ eep_config->adapter_info[5] = 0xBB; } else { + ASC_PRINT( +"AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n"); write_eep = 1; warn_code |= ASC_WARN_EEPROM_CHKSUM; } @@ -14092,7 +12716,7 @@ asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr; asc_dvc->cfg->disc_enable = eep_config->disc_enable; asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; - asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; + asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config); asc_dvc->start_motor = eep_config->start_motor; asc_dvc->dvc_cntl = eep_config->cntl; asc_dvc->no_scam = eep_config->no_scam; @@ -14136,8 +12760,8 @@ if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); } - eep_config->chip_scsi_id &= ASC_MAX_TID; - asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id; + ASC_EEP_SET_CHIP_ID(eep_config, ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID); + asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config); if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; @@ -14152,22 +12776,27 @@ } eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); if (write_eep) { - (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); + if ((i = AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type)) != + 0) { + ASC_PRINT1( +"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i); + } else { + ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM."); + } } return (warn_code); } -ASC_INITFUNC( -STATIC ushort, +STATIC ushort AscInitMicroCodeVar( ASC_DVC_VAR *asc_dvc ) -) { int i; ushort warn_code; PortAddr iop_base; ASC_PADDR phy_addr; + ASC_DCNT phy_size; iop_base = asc_dvc->iop_base; warn_code = 0; @@ -14176,26 +12805,27 @@ asc_dvc->cfg->sdtr_period_offset[i] ); } + AscInitQLinkVar(asc_dvc); AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, asc_dvc->cfg->disc_enable); AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); - if ((phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar *) asc_dvc->cfg->overrun_buf, - ASC_OVERRUN_BSIZE)) == 0L) { - asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR; - } else { - /* Align on an 8 byte boundary. */ - phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); - AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr); - AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D, - ASC_OVERRUN_BSIZE - 8); - } - asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base, - (ushort) ASCV_MC_DATE_W); - asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base, - (ushort) ASCV_MC_VER_W); + + /* Align overrun buffer on an 8 byte boundary. */ + phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf); + phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); + AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, + (uchar *) &phy_addr, 1); + phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8); + AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D, + (uchar *) &phy_size, 1); + + asc_dvc->cfg->mcode_date = + AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W); + asc_dvc->cfg->mcode_version = + AscReadLramWord(iop_base, (ushort) ASCV_MC_VER_W); + AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; @@ -14205,6 +12835,7 @@ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; return (warn_code); } + return (warn_code); } @@ -14368,16 +12999,15 @@ ushort *wbuf; int cfg_beg; int cfg_end; + int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; int s_addr; - int isa_pnp_wsize; wbuf = (ushort *) cfg_buf; sum = 0; - isa_pnp_wsize = 0; - for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar) s_addr); - sum += wval; - *wbuf = wval; + /* Read two config words; Byte-swapping done by AscReadEEPWord(). */ + for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { + *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); + sum += *wbuf; } if (bus_type & ASC_IS_VL) { cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; @@ -14386,12 +13016,24 @@ cfg_beg = ASC_EEP_DVC_CFG_BEG; cfg_end = ASC_EEP_MAX_DVC_ADDR; } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); - s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar) s_addr); - sum += wval; - *wbuf = wval; + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + wval = AscReadEEPWord( iop_base, ( uchar )s_addr ) ; + if (s_addr <= uchar_end_in_config) { + /* + * Swap all char fields - must unswap bytes already swapped + * by AscReadEEPWord(). + */ + *wbuf = le16_to_cpu(wval); + } else { + /* Don't swap word field at the end - cntl field. */ + *wbuf = wval; + } + sum += wval; /* Checksum treats all EEPROM data as words. */ } + /* + * Read the checksum word which will be compared against 'sum' + * by the caller. Word field already swapped. + */ *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr); return (sum); } @@ -14405,15 +13047,19 @@ ) { int n_error; - ushort *wbuf; + ushort *wbuf; + ushort word; ushort sum; int s_addr; int cfg_beg; int cfg_end; + int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; + wbuf = (ushort *) cfg_buf; n_error = 0; sum = 0; + /* Write two config words; AscWriteEEPWord() will swap bytes. */ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { sum += *wbuf; if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { @@ -14427,29 +13073,66 @@ cfg_beg = ASC_EEP_DVC_CFG_BEG; cfg_end = ASC_EEP_MAX_DVC_ADDR; } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); - s_addr++, wbuf++) { - sum += *wbuf; - if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { - n_error++; + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + if (s_addr <= uchar_end_in_config) { + /* + * This is a char field. Swap char fields before they are + * swapped again by AscWriteEEPWord(). + */ + word = cpu_to_le16(*wbuf); + if (word != AscWriteEEPWord( iop_base, (uchar) s_addr, word)) { + n_error++; + } + } else { + /* Don't swap word field at the end - cntl field. */ + if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) { + n_error++; + } } + sum += *wbuf; /* Checksum calculated from word values. */ } + /* Write checksum word. It will be swapped by AscWriteEEPWord(). */ *wbuf = sum; if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) { n_error++; } + + /* Read EEPROM back again. */ wbuf = (ushort *) cfg_buf; + /* + * Read two config words; Byte-swapping done by AscReadEEPWord(). + */ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { n_error++; } } - for (s_addr = cfg_beg; s_addr <= cfg_end; - s_addr++, wbuf++) { - if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) { + if (bus_type & ASC_IS_VL) { + cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; + cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; + } else { + cfg_beg = ASC_EEP_DVC_CFG_BEG; + cfg_end = ASC_EEP_MAX_DVC_ADDR; + } + for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { + if (s_addr <= uchar_end_in_config) { + /* + * Swap all char fields. Must unswap bytes already swapped + * by AscReadEEPWord(). + */ + word = le16_to_cpu(AscReadEEPWord(iop_base, (uchar) s_addr)); + } else { + /* Don't swap word field at the end - cntl field. */ + word = AscReadEEPWord(iop_base, (uchar) s_addr); + } + if (*wbuf != word) { n_error++; } } + /* Read checksum; Byte swapping not needed. */ + if (AscReadEEPWord(iop_base, (uchar) s_addr) != sum) { + n_error++; + } return (n_error); } @@ -14486,7 +13169,7 @@ uchar dvc_type; ASC_SCSI_BIT_ID_TYPE tid_bits; - dvc_type = inq->byte0.peri_dvc_type; + dvc_type = ASC_INQ_DVC_TYPE(inq); tid_bits = ASC_TIX_TO_TARGET_ID(tid_no); if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) @@ -14546,11 +13229,12 @@ asc_dvc->cfg->can_tagged_qng &= ~tid_bit; asc_dvc->use_tagged_qng &= ~tid_bit; - if (inq->byte3.rsp_data_fmt >= 2 || inq->byte2.ansi_apr_ver >= 2) { - if ((asc_dvc->cfg->sdtr_enable & tid_bit) && inq->byte7.Sync) { + if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) { + if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) { asc_dvc->init_sdtr |= tid_bit; } - if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) && inq->byte7.CmdQue) { + if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) && + ASC_INQ_CMD_QUEUE(inq)) { if (AscTagQueuingSafe(inq)) { asc_dvc->use_tagged_qng |= tid_bit; asc_dvc->cfg->can_tagged_qng |= tid_bit; @@ -14615,7 +13299,6 @@ } return (byte_data); } - STATIC ushort AscReadLramWord( PortAddr iop_base, @@ -14629,6 +13312,7 @@ return (word_data); } +#if CC_VERY_LONG_SG_LIST STATIC ASC_DCNT AscReadLramDWord( PortAddr iop_base, @@ -14644,6 +13328,7 @@ dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low; return (dword_data); } +#endif /* CC_VERY_LONG_SG_LIST */ STATIC void AscWriteLramWord( @@ -14658,30 +13343,13 @@ } STATIC void -AscWriteLramDWord( - PortAddr iop_base, - ushort addr, - ASC_DCNT dword_val +AscWriteLramByte( + PortAddr iop_base, + ushort addr, + uchar byte_val ) { - ushort word_val; - - AscSetChipLramAddr(iop_base, addr); - word_val = (ushort) dword_val; - AscSetChipLramData(iop_base, word_val); - word_val = (ushort) (dword_val >> 16); - AscSetChipLramData(iop_base, word_val); - return; -} - -STATIC void -AscWriteLramByte( - PortAddr iop_base, - ushort addr, - uchar byte_val -) -{ - ushort word_data; + ushort word_data; if (isodd_word(addr)) { addr--; @@ -14697,42 +13365,87 @@ return; } +/* + * Copy 2 bytes to LRAM. + * + * The source data is assumed to be in little-endian order in memory + * and is maintained in little-endian order when written to LRAM. + */ STATIC void -AscMemWordCopyToLram( +AscMemWordCopyPtrToLram( PortAddr iop_base, ushort s_addr, - ushort * s_buffer, + uchar *s_buffer, int words ) { + int i; + AscSetChipLramAddr(iop_base, s_addr); - DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words); + for (i = 0; i < 2 * words; i += 2) { + /* + * On a little-endian system the second argument below + * produces a little-endian ushort which is written to + * LRAM in little-endian order. On a big-endian system + * the second argument produces a big-endian ushort which + * is "transparently" byte-swapped by outpw() and written + * in little-endian order to LRAM. + */ + outpw(iop_base + IOP_RAM_DATA, + ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); + } return; } +/* + * Copy 4 bytes to LRAM. + * + * The source data is assumed to be in little-endian order in memory + * and is maintained in little-endian order when writen to LRAM. + */ STATIC void -AscMemDWordCopyToLram( +AscMemDWordCopyPtrToLram( PortAddr iop_base, ushort s_addr, - ASC_DCNT *s_buffer, + uchar *s_buffer, int dwords ) { + int i; + AscSetChipLramAddr(iop_base, s_addr); - DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords); + for (i = 0; i < 4 * dwords; i += 4) { + outpw(iop_base + IOP_RAM_DATA, + ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */ + outpw(iop_base + IOP_RAM_DATA, + ((ushort) s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */ + } return; } +/* + * Copy 2 bytes from LRAM. + * + * The source data is assumed to be in little-endian order in LRAM + * and is maintained in little-endian order when written to memory. + */ STATIC void -AscMemWordCopyFromLram( +AscMemWordCopyPtrFromLram( PortAddr iop_base, ushort s_addr, - ushort * d_buffer, + uchar *d_buffer, int words ) { + int i; + ushort word; + AscSetChipLramAddr(iop_base, s_addr); - DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words); + for (i = 0; i < 2 * words; i += 2) { + word = inpw(iop_base + IOP_RAM_DATA); + d_buffer[i] = word & 0xff; + d_buffer[i + 1] = (word >> 8) & 0xff; + } return; } @@ -14776,676 +13489,1078 @@ */ /* a_mcode.h */ + +/* Microcode buffer is kept after initialization for error recovery. */ STATIC unsigned char _adv_asc3550_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x18, 0xe4, - 0x00, 0xf6, 0x01, 0xf6, 0x18, 0x80, 0x48, 0x19, 0x02, 0x00, 0xff, 0xff, 0x03, 0xf6, 0x00, 0xfa, - 0xff, 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0x3a, 0x0e, 0x00, 0xea, 0x01, 0xe6, - 0x55, 0xf0, 0x03, 0x00, 0x08, 0x00, 0x18, 0xf4, 0x3e, 0x01, 0x3e, 0x57, 0x04, 0x00, 0x85, 0xf0, - 0x00, 0xe6, 0x00, 0xec, 0x1e, 0xf0, 0x32, 0xf0, 0x34, 0x19, 0x86, 0xf0, 0xd0, 0x01, 0xd5, 0xf0, - 0xde, 0x0c, 0x98, 0x57, 0xbc, 0x00, 0x0c, 0x1c, 0x0e, 0x13, 0x38, 0x54, 0xb1, 0xf0, 0xb4, 0x00, - 0x01, 0xfc, 0x03, 0xfc, 0xd8, 0x0c, 0x00, 0x57, 0x01, 0xf0, 0x02, 0x13, 0x03, 0xe6, 0x10, 0x00, - 0x18, 0x40, 0x3e, 0x1c, 0x6c, 0x01, 0x6e, 0x01, 0xbd, 0x00, 0xe0, 0x00, 0x02, 0x48, 0x02, 0x80, - 0x08, 0x12, 0x30, 0xe4, 0x3c, 0x00, 0x4e, 0x01, 0x64, 0x12, 0x80, 0x00, 0x9c, 0x15, 0xbb, 0x00, - 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x04, 0x12, 0x9e, 0x0f, 0xb6, 0x00, 0xb9, 0x54, 0xe2, 0x0f, - 0x00, 0x80, 0x06, 0xf7, 0x10, 0x44, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, 0x3c, 0x56, - 0x3e, 0x00, 0x4b, 0xe4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, - 0x76, 0x01, 0x78, 0x01, 0xe2, 0x0c, 0x00, 0x01, 0x02, 0xee, 0x02, 0xfc, 0x03, 0x58, 0x03, 0xf7, - 0x04, 0x80, 0x05, 0xfc, 0x08, 0x44, 0x09, 0xf0, 0x0f, 0x00, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, - 0x40, 0x00, 0x40, 0x15, 0x4b, 0xf4, 0x4e, 0x1c, 0x5b, 0xf0, 0x5d, 0xf0, 0xaa, 0x00, 0xbb, 0x55, - 0xbe, 0x00, 0xc0, 0x00, 0xe0, 0x08, 0xe0, 0x14, 0xec, 0x0f, 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a, - 0x05, 0x00, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, 0x08, 0x13, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, - 0x19, 0x00, 0x20, 0x00, 0x2a, 0x01, 0x30, 0x0e, 0x32, 0x1c, 0x36, 0x00, 0x45, 0x5a, 0x59, 0xf0, - 0x62, 0x0a, 0x69, 0x08, 0x72, 0x0b, 0x83, 0x59, 0xb8, 0xf0, 0xbd, 0x56, 0xcc, 0x12, 0xec, 0x17, - 0xee, 0x0f, 0xf0, 0x00, 0xf8, 0x17, 0x01, 0x48, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0x10, 0x04, 0xea, - 0x04, 0xf6, 0x04, 0xfc, 0x05, 0x80, 0x05, 0xe6, 0x06, 0x00, 0x06, 0x12, 0x0a, 0x10, 0x0b, 0xf0, - 0x0c, 0x10, 0x0c, 0xf0, 0x12, 0x10, 0x26, 0x0e, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44, - 0x40, 0x5c, 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x83, 0x55, 0x83, 0x5a, 0x8c, 0x14, - 0x8e, 0x0a, 0x90, 0x14, 0x91, 0x44, 0xa4, 0x00, 0xb0, 0x57, 0xb5, 0x00, 0xba, 0x00, 0xce, 0x45, - 0xd0, 0x00, 0xd8, 0x16, 0xe1, 0x00, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, - 0x03, 0xa1, 0x04, 0x13, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0, - 0x0c, 0x04, 0x0c, 0x12, 0x0c, 0x90, 0x10, 0x10, 0x10, 0x13, 0x12, 0x1c, 0x17, 0x00, 0x19, 0xe4, - 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01, - 0x26, 0x01, 0x2a, 0x12, 0x30, 0xe7, 0x34, 0x1c, 0x36, 0x1c, 0x38, 0x12, 0x41, 0x58, 0x43, 0x48, - 0x44, 0x55, 0x46, 0x1c, 0x4c, 0x0e, 0x4e, 0xe4, 0x52, 0x14, 0x5c, 0xf0, 0x72, 0x02, 0x74, 0x03, - 0x77, 0x57, 0x89, 0x48, 0x8e, 0x90, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x32, 0x9e, 0x00, 0xa8, 0x00, - 0xb9, 0x00, 0xba, 0x06, 0xbc, 0x12, 0xbf, 0x57, 0xc0, 0x01, 0xfe, 0x9c, 0xf0, 0x26, 0x02, 0xfe, - 0x00, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xfe, 0xc2, 0x01, 0xfe, 0x56, 0x19, 0x00, 0xfc, 0xfe, 0x80, - 0x01, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x6a, 0x13, 0xfe, 0x05, 0x05, 0xff, 0x40, 0x00, 0x00, 0x0d, - 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, - 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, - 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfc, 0x2b, 0x51, 0x0c, 0x01, 0xfe, 0xea, 0x0e, 0xfe, 0x04, 0xf7, - 0xfc, 0x51, 0x0c, 0x1d, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x20, 0xf0, 0xd0, 0x04, - 0x56, 0x4b, 0x02, 0xfe, 0x1c, 0x0d, 0x01, 0xfe, 0x7c, 0x0d, 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x04, - 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, 0x12, 0x4e, 0x12, 0xfe, 0xa6, 0x00, - 0xc5, 0xfe, 0x48, 0xf0, 0xfe, 0x7c, 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0x96, 0x02, 0xfe, 0x4a, 0xf0, - 0xfe, 0xb4, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x46, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x4c, 0x02, 0xfe, - 0x43, 0xf0, 0xfe, 0x3a, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x42, - 0x02, 0x09, 0x0c, 0x9e, 0x09, 0x06, 0x12, 0xbb, 0x02, 0x26, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, - 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x4c, 0x17, - 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xf7, 0x0e, 0x78, 0x01, 0xab, 0x02, 0x26, 0x17, 0x55, 0x4a, - 0xbd, 0x01, 0xfe, 0x60, 0x0f, 0x0e, 0x78, 0x01, 0x8b, 0xfe, 0xbd, 0x10, 0x0e, 0x78, 0x01, 0x8b, - 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x09, 0x06, 0x12, 0xbb, 0x2b, 0x22, 0x26, - 0xfe, 0x3d, 0xf0, 0xfe, 0xf8, 0x01, 0x27, 0xfe, 0x8a, 0x02, 0xfe, 0x5a, 0x1c, 0xd5, 0xfe, 0x14, - 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4a, 0xbd, 0x01, 0xfe, 0x50, 0x0f, 0x09, 0x06, 0x12, 0xbb, 0x02, - 0xfe, 0xc2, 0x01, 0x21, 0x2a, 0x05, 0x10, 0x35, 0xfe, 0x69, 0x10, 0x09, 0x06, 0x12, 0xbb, 0xfe, - 0x04, 0xec, 0x2a, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, 0x46, 0x7f, 0xfe, 0x05, 0xf6, 0xf7, 0x01, - 0xfe, 0x76, 0x16, 0x0a, 0x41, 0x89, 0x38, 0x11, 0x47, 0x1d, 0xca, 0x08, 0x1c, 0x09, 0x43, 0x01, - 0x71, 0x02, 0x26, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x2c, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, - 0xfe, 0x28, 0x10, 0x0e, 0xc0, 0x01, 0x15, 0xe6, 0x0e, 0x79, 0x01, 0x15, 0xfe, 0x49, 0x54, 0x74, - 0xfe, 0x12, 0x03, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x71, 0x02, 0x26, 0x2b, 0x7f, 0xfe, 0x02, 0xe8, - 0x2f, 0xfb, 0xfe, 0x9e, 0x43, 0xf0, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xd0, 0xfe, 0x40, 0x1c, - 0x22, 0xef, 0xfe, 0x26, 0xf0, 0xfe, 0x70, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x5e, 0x03, 0xfe, 0x11, - 0xf0, 0xd0, 0xfe, 0x0e, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x7e, 0x03, 0xe9, 0x13, 0xfe, 0x11, 0x00, - 0x02, 0x62, 0x2b, 0xfe, 0x48, 0x1c, 0xe9, 0x22, 0xef, 0x34, 0xef, 0xfe, 0x82, 0xf0, 0xfe, 0x84, - 0x03, 0x2d, 0x21, 0xbe, 0x6a, 0x16, 0xbe, 0x0e, 0x79, 0x01, 0x15, 0x6a, 0x7d, 0x08, 0x1c, 0x09, - 0x43, 0x01, 0x46, 0x11, 0x3d, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x71, 0xf5, 0x11, 0xfe, 0xe4, 0x00, - 0x2e, 0xfe, 0xca, 0x03, 0x22, 0x32, 0x1f, 0xfe, 0xda, 0x03, 0x01, 0x4c, 0xcb, 0xfe, 0xea, 0x03, - 0x6b, 0x92, 0xcf, 0xfe, 0xaa, 0x06, 0x02, 0x28, 0x04, 0x78, 0x29, 0x18, 0xfe, 0x1c, 0x05, 0x17, - 0x85, 0x01, 0x44, 0x01, 0x97, 0x01, 0x9a, 0x34, 0xfe, 0x5c, 0x02, 0x02, 0xee, 0xe9, 0x2b, 0x51, - 0x19, 0xfe, 0x67, 0x1b, 0xfb, 0xf0, 0xfe, 0x48, 0x1c, 0x8c, 0x01, 0xfa, 0xac, 0xfe, 0x96, 0xf0, - 0xfe, 0x24, 0x04, 0x2e, 0xfe, 0x28, 0x04, 0x34, 0x26, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x18, - 0xfe, 0x08, 0x05, 0x3e, 0x90, 0x9f, 0x2f, 0x82, 0x6e, 0x22, 0x32, 0x1f, 0x28, 0x04, 0x78, 0x29, - 0xfe, 0x10, 0x12, 0x17, 0x85, 0x01, 0x44, 0x34, 0xfe, 0x5c, 0x02, 0x02, 0xee, 0x31, 0xfe, 0xa0, - 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, 0x12, 0x0a, 0x07, 0x06, 0xfe, 0x56, 0x12, 0x23, 0x24, 0x91, - 0x01, 0x0b, 0x82, 0x6e, 0x1f, 0xfe, 0xd8, 0x04, 0x23, 0x24, 0x91, 0x01, 0x0b, 0x1f, 0x28, 0x23, - 0x24, 0xb3, 0xfe, 0x4c, 0x44, 0xfe, 0x32, 0x12, 0x57, 0xfe, 0x44, 0x48, 0x08, 0xd6, 0xfe, 0x4c, - 0x54, 0x74, 0xfe, 0x08, 0x05, 0x7f, 0x9f, 0x2f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x48, - 0x13, 0x3f, 0x05, 0xfe, 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x07, 0x06, 0xe5, 0xfe, 0x06, 0x10, - 0x23, 0x24, 0xb3, 0x0a, 0x07, 0x37, 0xda, 0x17, 0xa4, 0x0a, 0x07, 0x06, 0x4b, 0x17, 0xfe, 0x0d, - 0x00, 0x01, 0x44, 0x34, 0xfe, 0xc0, 0x0c, 0x02, 0x28, 0x39, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, - 0x90, 0xb0, 0x03, 0x17, 0xa4, 0x01, 0x44, 0x34, 0x26, 0x22, 0x26, 0x02, 0xfe, 0x10, 0x05, 0xfe, - 0x42, 0x5b, 0x51, 0x19, 0xfe, 0x46, 0x59, 0xfb, 0xf0, 0x17, 0x45, 0xfe, 0x07, 0x80, 0xfe, 0x31, - 0x44, 0x0a, 0x07, 0x0c, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x05, 0x19, 0xfe, 0x70, 0x12, 0x6d, - 0x07, 0x06, 0xfe, 0x60, 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x29, 0x18, 0xfe, 0xa8, 0x05, 0xfe, 0x31, - 0xe4, 0x70, 0x6d, 0x07, 0x0c, 0xfe, 0x4a, 0x13, 0x04, 0xfe, 0xa0, 0x00, 0x29, 0xfe, 0x42, 0x12, - 0x5a, 0x2e, 0xfe, 0x68, 0x05, 0x22, 0x32, 0xf1, 0x01, 0x0b, 0x25, 0xfe, 0xc0, 0x05, 0x11, 0xfe, - 0xe3, 0x00, 0x2d, 0x6d, 0xfe, 0x4a, 0xf0, 0xfe, 0x92, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x8c, 0x05, - 0xa8, 0x20, 0xfe, 0x21, 0x00, 0xa6, 0x20, 0xfe, 0x22, 0x00, 0x9e, 0x20, 0x89, 0xfe, 0x09, 0x48, - 0x01, 0x0b, 0x25, 0xfe, 0xc0, 0x05, 0xfe, 0xe2, 0x08, 0x6d, 0x07, 0xd9, 0x4b, 0x01, 0x96, 0x20, - 0x06, 0x16, 0xe0, 0x4a, 0xfe, 0x27, 0x01, 0x0a, 0x07, 0x37, 0xe1, 0x4e, 0x01, 0xb9, 0x17, 0xa4, - 0x0a, 0x07, 0x06, 0x4b, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x44, 0x01, 0x97, 0x01, 0x9a, 0x34, 0xfe, - 0xc0, 0x0c, 0x02, 0x28, 0x04, 0xfe, 0x9c, 0x00, 0x29, 0xfe, 0x3e, 0x12, 0x04, 0x53, 0x29, 0xfe, - 0x36, 0x13, 0x4e, 0x01, 0xb9, 0x25, 0xfe, 0x38, 0x06, 0x0e, 0x06, 0x6d, 0x07, 0x1a, 0xfe, 0x02, - 0x12, 0x77, 0x01, 0xfe, 0x26, 0x14, 0x1f, 0xfe, 0x2e, 0x06, 0x11, 0xc2, 0x01, 0x4c, 0x11, 0xfe, - 0xe5, 0x00, 0x04, 0x53, 0xbc, 0x0f, 0x53, 0x04, 0xf6, 0x29, 0xfe, 0x62, 0x12, 0x04, 0x4d, 0x29, - 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x9e, 0x18, 0x01, 0xfe, 0xf0, 0x18, 0xe7, 0xa3, 0x1a, 0x08, 0x63, - 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, 0x50, 0xc9, 0xa3, 0x6c, 0x4e, 0x01, 0xb9, 0x25, 0xfe, - 0xa2, 0x06, 0x6d, 0x07, 0x1e, 0xa5, 0x95, 0x0e, 0x55, 0x01, 0xfe, 0x54, 0x14, 0x1f, 0xfe, 0x98, - 0x06, 0x11, 0xc2, 0x01, 0x4c, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x4d, 0xbc, 0x0f, 0x4d, 0x09, 0x06, - 0x01, 0xb9, 0xf5, 0x73, 0x8c, 0x01, 0xfa, 0xac, 0x11, 0xfe, 0xe2, 0x00, 0x2e, 0xf9, 0x22, 0x32, - 0xcf, 0xfe, 0xd6, 0x06, 0x81, 0xfe, 0x74, 0x07, 0xcb, 0xfe, 0x7c, 0x07, 0x6b, 0x92, 0x02, 0x28, - 0x0a, 0x07, 0x0c, 0xfe, 0x2e, 0x12, 0x14, 0x19, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, - 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01, 0x0b, 0x14, 0x00, 0x02, 0xfe, 0x4c, - 0x08, 0x68, 0x07, 0x1e, 0xe5, 0x0a, 0x07, 0x1e, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b, 0x00, 0x01, - 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x00, 0x01, 0x0b, 0x14, 0x06, 0x01, - 0x0b, 0x14, 0x00, 0x02, 0xfe, 0x2a, 0x0b, 0x77, 0xfe, 0x9a, 0x81, 0x67, 0x89, 0xfe, 0x09, 0x6f, - 0xfe, 0x93, 0x45, 0x18, 0xfe, 0x84, 0x07, 0x2e, 0xfe, 0x5c, 0x07, 0x22, 0x32, 0xcf, 0xfe, 0x54, - 0x07, 0x6b, 0x92, 0x81, 0xfe, 0x74, 0x07, 0x02, 0x28, 0x01, 0x4c, 0x02, 0xf9, 0x14, 0x1a, 0x02, - 0xf9, 0xfe, 0x9c, 0xf7, 0xfe, 0xec, 0x07, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x75, 0xfe, 0xd2, - 0x07, 0x0f, 0x5d, 0x12, 0x5e, 0x0a, 0x41, 0x70, 0x38, 0x01, 0xfe, 0x34, 0x18, 0x05, 0x10, 0x83, - 0xfe, 0x83, 0xe7, 0x88, 0xa6, 0xfe, 0x03, 0x40, 0x0a, 0x41, 0x45, 0x38, 0x01, 0xc1, 0xaf, 0xfe, - 0x1f, 0x40, 0x16, 0x61, 0x01, 0xfe, 0xde, 0x12, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x34, - 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0f, 0x5b, 0x12, 0x5c, 0xd2, 0xf2, - 0x0f, 0x3a, 0x12, 0x3b, 0xfe, 0x60, 0x10, 0x0a, 0x07, 0x70, 0xe1, 0xfe, 0x2c, 0x90, 0xfe, 0xae, - 0x90, 0x0f, 0x5d, 0x12, 0x5e, 0x0a, 0x07, 0x45, 0xc9, 0x01, 0xc1, 0xfe, 0x1f, 0x80, 0x16, 0x61, - 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, 0x0f, 0x5f, 0x12, 0x60, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, - 0x0f, 0x5b, 0x12, 0x5c, 0xa2, 0x07, 0x45, 0x2c, 0xd2, 0xf2, 0x0f, 0x3a, 0x12, 0x3b, 0xa8, 0xfe, - 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0f, 0x3a, 0x12, 0x3b, 0x0f, 0x42, 0x12, 0x58, 0x0a, 0x41, 0x1a, - 0x38, 0x2b, 0x08, 0x80, 0x2e, 0xfe, 0x62, 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x76, 0x08, 0x9b, 0x18, - 0x32, 0x2b, 0x52, 0xfe, 0xed, 0x10, 0xa7, 0xfe, 0x9a, 0x08, 0xa9, 0xfe, 0xb6, 0x08, 0x81, 0xfe, - 0x8e, 0x08, 0xcb, 0xfe, 0x94, 0x08, 0x6b, 0x92, 0x02, 0x28, 0x01, 0x4c, 0xfe, 0xc9, 0x10, 0x14, - 0x1a, 0xfe, 0xc9, 0x10, 0x68, 0x07, 0x06, 0xfe, 0x10, 0x12, 0x68, 0x07, 0x0c, 0x40, 0x0a, 0x07, - 0x0c, 0xfe, 0x7e, 0x12, 0xfe, 0x2e, 0x1c, 0xaa, 0x68, 0x07, 0x06, 0x40, 0x68, 0x07, 0x0c, 0xfe, - 0x6a, 0x12, 0xfe, 0x2c, 0x1c, 0xa2, 0x07, 0x45, 0xd4, 0xa2, 0x41, 0x45, 0xfe, 0x05, 0x40, 0xd2, - 0xf2, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0xfe, 0xaa, 0xf0, 0xfe, 0x4e, 0x09, 0xfe, 0xac, 0xf0, - 0xfe, 0xee, 0x08, 0xfe, 0x92, 0x10, 0xe3, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xfa, 0x08, - 0x02, 0xfe, 0x5c, 0x0a, 0xe4, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xb8, 0xfe, 0x6b, 0x18, 0x1b, - 0xfe, 0x00, 0xfe, 0xda, 0xc5, 0xfe, 0xd2, 0xf0, 0xb8, 0xfe, 0x76, 0x18, 0x1b, 0x19, 0x18, 0xb8, - 0x04, 0xdf, 0x1b, 0x06, 0x18, 0xb8, 0xa7, 0x7a, 0xa9, 0x7a, 0xe3, 0xe4, 0xfe, 0xb1, 0x10, 0x8c, - 0x5a, 0x39, 0x17, 0xa4, 0x01, 0x44, 0x13, 0xfe, 0x35, 0x00, 0x34, 0x62, 0x13, 0x8d, 0x02, 0x62, - 0xfe, 0x74, 0x18, 0x1b, 0xfe, 0x00, 0xf8, 0x18, 0x7a, 0x51, 0x1e, 0x01, 0xfe, 0x7c, 0x0d, 0xd1, - 0x08, 0x1c, 0x09, 0x43, 0x01, 0x71, 0x21, 0x2f, 0x3e, 0x51, 0x19, 0x02, 0x7a, 0xfe, 0x98, 0x80, - 0xd7, 0x0c, 0x27, 0xfe, 0x3e, 0x0a, 0x0a, 0x07, 0x70, 0xfe, 0x82, 0x12, 0x0a, 0x07, 0x1a, 0xfe, - 0x66, 0x13, 0x21, 0x61, 0x6a, 0xc8, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, - 0x04, 0x91, 0xfe, 0x86, 0x91, 0x64, 0x2f, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x75, 0xfe, 0xea, - 0x08, 0x04, 0x5d, 0x30, 0x5e, 0x0f, 0xae, 0x12, 0x8d, 0x9c, 0x5d, 0x9d, 0x5e, 0x01, 0xc1, 0xaf, - 0x64, 0x2f, 0x16, 0x61, 0xa1, 0x42, 0x69, 0x58, 0x65, 0x5f, 0x31, 0x60, 0xe8, 0xfe, 0xe5, 0x55, - 0xfe, 0x04, 0xfa, 0x42, 0xfe, 0x05, 0xfa, 0x58, 0x01, 0xfe, 0xde, 0x12, 0xfe, 0x36, 0x10, 0x2d, - 0x0f, 0xae, 0x0f, 0x8d, 0x65, 0x5f, 0x31, 0x60, 0xaa, 0x0a, 0x07, 0x1a, 0x18, 0xfe, 0xea, 0x08, - 0x65, 0x3a, 0x31, 0x3b, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x38, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x10, - 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x7a, 0x0a, 0x07, 0x1a, 0x18, - 0xfe, 0xea, 0x08, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x38, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x77, - 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x3f, 0x05, 0xc3, 0x18, 0xfe, 0xf6, 0x08, - 0x11, 0xc3, 0xfe, 0x98, 0x80, 0xd7, 0x0c, 0xfe, 0x14, 0x13, 0x04, 0x3a, 0x30, 0x3b, 0x75, 0xfe, - 0xf6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x7a, 0x2d, 0x4e, 0xfe, 0x19, 0x80, 0xfe, - 0xf1, 0x10, 0x0a, 0x07, 0x0c, 0xa5, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x8e, 0x10, 0xfe, - 0x6c, 0x19, 0x9c, 0x3a, 0xfe, 0xed, 0x19, 0x9d, 0x3b, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, - 0x6b, 0x18, 0x1b, 0xfe, 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc5, 0xfe, 0xd2, 0xf0, 0xfe, 0xd6, - 0x0a, 0xfe, 0x76, 0x18, 0x1b, 0x19, 0xce, 0x04, 0xdf, 0x1b, 0x06, 0x84, 0x13, 0xfe, 0x16, 0x00, - 0x02, 0x62, 0xfe, 0xd1, 0xf0, 0xfe, 0xe8, 0x0a, 0x17, 0x80, 0x01, 0x44, 0x13, 0xd6, 0xfe, 0x42, - 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xee, 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xfa, 0x0a, - 0x13, 0xfe, 0x22, 0x00, 0x02, 0x62, 0xfe, 0xcb, 0xf0, 0xfe, 0x06, 0x0b, 0x13, 0xfe, 0x24, 0x00, - 0x02, 0x62, 0xfe, 0xd0, 0xf0, 0xfe, 0x10, 0x0b, 0x13, 0x88, 0xd8, 0xfe, 0xcf, 0xf0, 0xfe, 0x1a, - 0x0b, 0x13, 0x89, 0xd3, 0xfe, 0xcc, 0xf0, 0xfe, 0x2a, 0x0b, 0xfe, 0x84, 0x80, 0xd7, 0x1a, 0x4b, - 0x13, 0xfe, 0x12, 0x00, 0x2b, 0x08, 0x80, 0x2e, 0xfe, 0x30, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x44, - 0x0b, 0x9b, 0x18, 0x32, 0x2b, 0x52, 0xfe, 0xed, 0x10, 0xa7, 0x28, 0xa9, 0x28, 0x2b, 0xf5, 0x2e, - 0xfe, 0x50, 0x0b, 0x22, 0x32, 0x81, 0xfe, 0x6c, 0x0b, 0x6b, 0x92, 0xa7, 0xfe, 0xec, 0x07, 0xa9, - 0xfe, 0xec, 0x07, 0x02, 0x28, 0x01, 0x4c, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xe3, 0xe4, - 0x8c, 0x82, 0x6e, 0xfe, 0x89, 0xf0, 0x28, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0x01, 0x0b, 0x82, 0x6e, - 0x1f, 0x28, 0x23, 0x24, 0x91, 0x34, 0xfe, 0xa8, 0x0b, 0x22, 0x32, 0x02, 0xfe, 0x9c, 0x0b, 0x9b, - 0x40, 0x13, 0xfe, 0x42, 0x00, 0x02, 0x62, 0xa0, 0x06, 0xfe, 0x81, 0x49, 0x96, 0x0a, 0x07, 0x0c, - 0xfe, 0x5a, 0x13, 0x13, 0x00, 0x59, 0x0c, 0xfe, 0x6a, 0x12, 0x59, 0xfe, 0x28, 0x00, 0x27, 0xfe, - 0xee, 0x0c, 0x0e, 0x79, 0x01, 0x15, 0x05, 0x00, 0x84, 0x36, 0xfe, 0x28, 0x00, 0x02, 0xfe, 0xee, - 0x0c, 0x01, 0x97, 0x01, 0x9a, 0x0e, 0xc0, 0x01, 0xfe, 0x44, 0x0e, 0xb2, 0x08, 0x3d, 0x09, 0x99, - 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, 0x02, 0x26, 0x13, 0xfe, 0x44, 0x00, - 0x59, 0x0c, 0xa5, 0x36, 0x0c, 0xfe, 0xc0, 0x10, 0x01, 0x96, 0x36, 0x0c, 0xfe, 0xb6, 0x10, 0x01, - 0x96, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x36, 0x0c, 0x13, 0xfe, 0x43, 0x00, - 0xfe, 0xa2, 0x10, 0x0a, 0x41, 0x0c, 0x38, 0x01, 0x97, 0x01, 0x9a, 0xb2, 0x08, 0x3d, 0x09, 0x99, - 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, 0x7b, 0x51, 0x0c, 0xb2, 0x1d, 0xca, 0x02, - 0xfe, 0x48, 0x03, 0x0a, 0x07, 0x0c, 0xce, 0x36, 0x0c, 0x13, 0x00, 0xfe, 0x54, 0x10, 0x68, 0x07, - 0x1e, 0xfe, 0x50, 0x12, 0x0a, 0x07, 0x1e, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, - 0xfe, 0xac, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0xb2, 0x0c, 0x0a, 0x41, 0x1e, 0x38, - 0xfe, 0x95, 0x10, 0x13, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0c, 0x77, 0xfe, 0x26, 0x10, 0x13, - 0xfe, 0x13, 0x00, 0xd3, 0x13, 0xfe, 0x47, 0x00, 0xa6, 0x13, 0xfe, 0x41, 0x00, 0x9e, 0x13, 0xfe, - 0x24, 0x00, 0x04, 0x78, 0x29, 0x27, 0xee, 0x77, 0xfe, 0x04, 0xe6, 0x1e, 0xfe, 0x9d, 0x41, 0xfe, - 0x1c, 0x42, 0xb2, 0x01, 0xea, 0x02, 0x26, 0xd5, 0x17, 0x0c, 0x4a, 0xf4, 0xdd, 0x17, 0xfe, 0x31, - 0x00, 0x4a, 0xbd, 0x01, 0xfe, 0x50, 0x0f, 0x02, 0xfe, 0xc2, 0x01, 0x1d, 0xfe, 0x06, 0xec, 0xf8, - 0x86, 0x36, 0x37, 0xbf, 0x35, 0x1d, 0xfe, 0x06, 0xea, 0xf8, 0xfe, 0x47, 0x4b, 0x95, 0xfe, 0x75, - 0x57, 0x04, 0x56, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0e, 0x79, 0xfe, 0xf4, 0x14, 0x4e, 0xe6, - 0x0e, 0xc0, 0xfe, 0xea, 0x14, 0xfe, 0x49, 0x54, 0x8f, 0xfe, 0x62, 0x0d, 0x0e, 0x1c, 0xfe, 0xde, - 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x48, 0x03, 0x0e, 0x56, 0xfe, 0xc8, 0x14, 0x86, 0x36, 0x37, - 0xbf, 0x35, 0x1d, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x26, 0x21, 0x2a, 0x05, 0x10, 0xfe, - 0x78, 0x12, 0x2d, 0x16, 0x55, 0x16, 0xad, 0x21, 0x47, 0x4e, 0x4a, 0x47, 0x9b, 0xfe, 0x0c, 0x13, - 0xfe, 0xbc, 0xf0, 0xfe, 0xfe, 0x0d, 0x08, 0x06, 0x16, 0x55, 0x01, 0xfe, 0x06, 0x16, 0x04, 0xfe, - 0x38, 0x01, 0x30, 0xfe, 0x3a, 0x01, 0x75, 0xfe, 0x02, 0x0e, 0x04, 0xfe, 0x38, 0x01, 0x1b, 0xfe, - 0xf0, 0xff, 0x0f, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0f, 0xfe, 0x62, 0x01, 0x20, 0x06, - 0x16, 0x47, 0xfe, 0x04, 0xec, 0x2a, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, 0x46, 0x7f, 0xfe, 0x05, - 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x76, 0x16, 0x11, 0x47, 0xca, 0x08, 0x06, 0x03, 0x2d, 0x03, - 0x21, 0x55, 0xfe, 0xf7, 0x12, 0x21, 0xad, 0x6a, 0x16, 0xad, 0x05, 0x80, 0xfe, 0x93, 0x13, 0xfe, - 0x24, 0x1c, 0x17, 0x19, 0x4a, 0xf4, 0xdd, 0xfe, 0xd9, 0x10, 0x93, 0xfe, 0x03, 0xdc, 0xfe, 0x73, - 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x93, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, - 0xfe, 0x03, 0x57, 0x93, 0x2d, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0x93, 0x7d, 0x03, 0x01, - 0xfe, 0xae, 0x16, 0x3f, 0x05, 0x47, 0xfe, 0x0a, 0x13, 0x08, 0x1c, 0x09, 0x43, 0xd3, 0x01, 0x97, - 0x01, 0x9a, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11, 0xfe, 0xe9, 0x00, 0x0a, 0x07, 0x89, 0xfe, - 0x52, 0x13, 0x01, 0xfe, 0x38, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0x0f, 0xfe, 0x64, 0x01, - 0xfe, 0x16, 0x90, 0x0f, 0xfe, 0x66, 0x01, 0x0a, 0x07, 0x45, 0xe5, 0xfe, 0x03, 0x80, 0x52, 0x3e, - 0x11, 0x76, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x90, 0x01, 0x71, 0xfe, 0x62, 0x08, 0x6a, 0x3e, 0x11, - 0x76, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x90, 0x01, 0x71, 0x64, 0x2f, 0x11, 0x76, 0x08, 0x2a, 0x09, - 0x3c, 0x1d, 0x90, 0x01, 0x7b, 0x03, 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, - 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x04, 0xfe, - 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x20, 0x6c, 0x16, 0xf8, 0x2d, 0x0f, 0x53, 0x0f, - 0x4d, 0x20, 0x10, 0x16, 0x2a, 0x16, 0x3c, 0x57, 0xa0, 0xd6, 0x08, 0x2a, 0x09, 0x3c, 0x1d, 0x01, - 0x7b, 0x7f, 0x11, 0x76, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x2a, 0x0f, 0xd5, 0x8c, 0xfe, - 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x1d, 0xfe, 0x0c, 0x14, 0x86, 0xfe, 0x07, - 0xe6, 0x37, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x96, 0x0e, 0x3d, 0x01, 0x15, 0x05, - 0x10, 0x2c, 0x0e, 0x1c, 0x01, 0x15, 0x05, 0x10, 0xda, 0xfe, 0x44, 0x58, 0x3e, 0xfe, 0x01, 0xec, - 0xbd, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1e, 0x9f, 0x2f, 0x01, 0xea, - 0xfe, 0xc9, 0x10, 0x03, 0x2b, 0x82, 0x6e, 0x23, 0x24, 0xb3, 0x05, 0x1e, 0xfe, 0x48, 0x12, 0x05, - 0x0c, 0xfe, 0x4c, 0x12, 0x05, 0x19, 0xfe, 0x30, 0x12, 0x05, 0xcc, 0x18, 0xfe, 0xf4, 0x10, 0x05, - 0xfe, 0x23, 0x00, 0x18, 0xfe, 0x00, 0x11, 0x05, 0x06, 0x18, 0xfe, 0x5e, 0x11, 0x05, 0x1a, 0xfe, - 0x12, 0x12, 0x05, 0x00, 0x18, 0x28, 0x17, 0xcc, 0x01, 0x44, 0xc6, 0x39, 0x01, 0x0b, 0x81, 0x4c, - 0x03, 0x39, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x26, 0x39, 0x3f, 0x05, 0xc3, 0xfe, 0xe3, 0x13, 0x65, - 0x3a, 0x31, 0x3b, 0x75, 0xfe, 0xb2, 0x10, 0x0a, 0x07, 0x70, 0xfe, 0x72, 0x12, 0xa1, 0x42, 0x69, - 0x58, 0xe8, 0xfe, 0xe5, 0x55, 0x8f, 0xfe, 0x7c, 0x10, 0x21, 0x61, 0xfe, 0x26, 0x13, 0x04, 0xae, - 0x30, 0x8d, 0x75, 0xfe, 0xd2, 0x0c, 0x0f, 0x5d, 0x12, 0x5e, 0x2d, 0x0f, 0xae, 0x0f, 0x8d, 0x01, - 0xc1, 0x20, 0x6c, 0x52, 0x16, 0x61, 0x01, 0xfe, 0xde, 0x12, 0xa1, 0x42, 0x69, 0x58, 0xfe, 0x04, - 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x42, 0xfe, 0x05, 0xfa, 0x58, 0xfe, 0x91, 0x10, 0x04, - 0x5f, 0x30, 0x60, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0f, 0x5f, 0x12, 0x60, 0xa8, 0xa1, 0x42, - 0x69, 0x58, 0xe8, 0xfe, 0xe5, 0x55, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, - 0x0f, 0x5b, 0x12, 0x5c, 0x0a, 0x07, 0x70, 0xfe, 0x1e, 0x12, 0x21, 0x61, 0xfe, 0x1f, 0x40, 0x04, - 0x5d, 0x30, 0x5e, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, 0x5f, 0x30, 0x60, 0xfe, 0x34, 0x50, - 0xfe, 0xb6, 0x50, 0x04, 0x5b, 0x30, 0x5c, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x04, 0x3a, 0x30, - 0x3b, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0x98, 0x20, 0x06, 0x16, 0xf3, 0x02, 0x7c, 0x39, - 0x01, 0x0b, 0x1f, 0x4f, 0x23, 0x24, 0xb3, 0x05, 0x06, 0x27, 0x4f, 0x3f, 0x05, 0xc3, 0x27, 0x7c, - 0x01, 0xfa, 0x1b, 0x50, 0x18, 0x4f, 0x0a, 0x07, 0x0c, 0xdc, 0x65, 0x3a, 0x31, 0x3b, 0xfe, 0x0a, - 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x9c, 0x3a, 0x9d, 0x3b, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, - 0x7c, 0xfe, 0x19, 0x81, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7c, 0x39, 0x01, 0x0b, 0x1f, - 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0x59, 0x19, 0xfe, 0x94, 0x12, 0x59, 0x0c, 0x4b, - 0x02, 0x4f, 0x2e, 0xfe, 0x7e, 0x11, 0x22, 0x32, 0x1f, 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0x91, 0x05, - 0x19, 0x27, 0x4f, 0x01, 0x0b, 0x1f, 0xfe, 0xf6, 0x0f, 0x23, 0x24, 0xfe, 0xe8, 0x09, 0x57, 0x04, - 0xfe, 0x9c, 0x00, 0x29, 0x35, 0xfe, 0xbb, 0x45, 0x59, 0x00, 0x40, 0x36, 0x06, 0xa0, 0x50, 0xfe, - 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xac, 0x3f, 0x05, 0xc2, 0xfe, 0x16, 0x13, 0x04, 0xf6, 0x29, 0xce, - 0x04, 0x4d, 0x29, 0x35, 0x5a, 0x02, 0x7c, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, 0x14, 0xfe, 0x03, 0x17, - 0x04, 0x53, 0xbc, 0x0f, 0x53, 0x5a, 0x39, 0x01, 0x0b, 0x25, 0x98, 0x01, 0xfe, 0x26, 0x14, 0x02, - 0x98, 0x2e, 0x40, 0x22, 0x32, 0x1f, 0x4f, 0x23, 0x24, 0x91, 0x05, 0x06, 0x27, 0x4f, 0xfe, 0xf6, - 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, 0xac, 0xfe, 0x4a, 0xf4, 0x0c, 0x18, - 0x4f, 0xfe, 0x4a, 0xf4, 0x06, 0xd1, 0x3f, 0x05, 0xc2, 0xc9, 0x02, 0x7c, 0x04, 0x4d, 0xbc, 0x0f, - 0x4d, 0x5a, 0x39, 0x01, 0x0b, 0x25, 0x98, 0x01, 0xfe, 0x54, 0x14, 0x02, 0x98, 0x25, 0xfe, 0x70, - 0x12, 0x73, 0xf1, 0x73, 0x03, 0x34, 0xfe, 0x6c, 0x12, 0x6b, 0xfe, 0x6c, 0x12, 0x5a, 0x39, 0x01, - 0x0b, 0xfe, 0xe3, 0x10, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, 0xfe, 0xff, 0x7f, - 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0x1b, - 0x50, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, - 0x03, 0x08, 0x63, 0xff, 0x02, 0x00, 0x57, 0x66, 0x7e, 0xfe, 0x0b, 0x58, 0x03, 0x0e, 0x53, 0x01, - 0x8b, 0x0e, 0x4d, 0x01, 0x8b, 0x03, 0xc8, 0x1b, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, - 0x1a, 0x66, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x64, 0x2f, - 0x0f, 0x5b, 0x12, 0x5c, 0x9c, 0x5f, 0x9d, 0x60, 0x03, 0xfe, 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, - 0xe1, 0x1a, 0xb6, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x9e, 0x18, 0xfe, 0x42, 0x48, 0x77, 0x57, - 0x95, 0x01, 0x0b, 0x1f, 0xfe, 0x1e, 0x14, 0x23, 0x24, 0xfe, 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, - 0x0b, 0x1f, 0xfe, 0x1e, 0x14, 0x23, 0x24, 0xfe, 0xe8, 0x0a, 0x04, 0xf6, 0x29, 0xfe, 0xc4, 0x12, - 0x2d, 0xb1, 0x1e, 0xdc, 0x59, 0xcd, 0x74, 0xfe, 0x6c, 0x13, 0x4b, 0x08, 0x06, 0x09, 0xcd, 0xa0, - 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa6, 0xff, 0x02, 0x83, 0x55, 0xb1, - 0x19, 0xfe, 0x12, 0x13, 0x72, 0xfe, 0x30, 0x00, 0x8f, 0xfe, 0xc6, 0x13, 0x09, 0x85, 0x08, 0x06, - 0xfe, 0x56, 0x10, 0xb1, 0x0c, 0xfe, 0x16, 0x13, 0x72, 0xfe, 0x64, 0x00, 0x8f, 0xfe, 0xc6, 0x13, - 0x0e, 0xfe, 0x64, 0x00, 0x09, 0x88, 0x08, 0x06, 0xfe, 0x28, 0x10, 0xb1, 0x06, 0xfe, 0x60, 0x13, - 0x72, 0xfe, 0xc8, 0x00, 0x8f, 0xfe, 0xc6, 0x13, 0x0e, 0xfe, 0xc8, 0x00, 0x09, 0x55, 0x08, 0x06, - 0xa8, 0x72, 0xfe, 0x90, 0x01, 0xed, 0xfe, 0xd2, 0x13, 0x95, 0xaa, 0xfe, 0x43, 0xf4, 0xad, 0xfe, - 0x56, 0xf0, 0xfe, 0xe4, 0x13, 0xfe, 0x04, 0xf4, 0x63, 0xfe, 0x43, 0xf4, 0x88, 0xfe, 0xf3, 0x10, - 0xb0, 0x01, 0xfe, 0xae, 0x12, 0x1b, 0x50, 0xd4, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6c, 0xed, - 0xfe, 0x18, 0x14, 0xa3, 0x6c, 0xfe, 0x14, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x1a, 0xed, - 0xfe, 0x18, 0x14, 0xa3, 0x1a, 0x9e, 0x57, 0x95, 0x08, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, - 0x03, 0x57, 0x08, 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0b, 0x25, 0xec, 0x14, 0x0c, 0x01, 0x0b, 0x25, - 0xec, 0x14, 0x19, 0x01, 0x0b, 0x25, 0xec, 0x73, 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x03, 0x14, 0x06, - 0x01, 0x0b, 0x25, 0xb7, 0x14, 0x19, 0x01, 0x0b, 0x25, 0xb7, 0x14, 0x06, 0x01, 0x0b, 0x25, 0xb7, - 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x25, 0xb7, 0x73, 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x03, 0x57, 0x03, - 0x21, 0xe0, 0x05, 0x06, 0xfe, 0x44, 0x13, 0xaf, 0x16, 0xe0, 0xfe, 0x49, 0xf4, 0x00, 0x4b, 0x73, - 0xc6, 0x5a, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x0b, 0x3f, 0x05, 0xfe, 0xe3, 0x00, - 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0xd6, 0x14, 0x2d, 0x16, 0xf3, 0x01, 0x4c, 0x21, 0xf3, 0x05, 0x06, - 0x40, 0x0a, 0x41, 0x06, 0x38, 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, - 0x10, 0xfe, 0x1e, 0x12, 0x48, 0xe7, 0x8e, 0x01, 0x2c, 0xfe, 0x90, 0x4d, 0xde, 0x10, 0xfe, 0xc5, - 0x59, 0x01, 0x2c, 0xfe, 0x8d, 0x56, 0xb6, 0x48, 0x03, 0x48, 0x31, 0x8a, 0x01, 0x15, 0x48, 0x8e, - 0x01, 0x2c, 0xe2, 0x10, 0xde, 0x10, 0x31, 0x54, 0x72, 0x1c, 0x84, 0x0e, 0x56, 0x01, 0xab, 0x03, - 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0xc3, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1a, 0x12, 0x48, 0xe7, - 0x8e, 0x01, 0x2c, 0xe2, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, 0x59, 0x01, 0x2c, 0x48, 0x03, 0x48, - 0x31, 0x54, 0x01, 0x15, 0x48, 0x8e, 0x01, 0x2c, 0xe2, 0x10, 0xde, 0x10, 0x31, 0x54, 0x72, 0x1c, - 0x84, 0x0e, 0x56, 0x01, 0xab, 0x03, 0x0f, 0x54, 0x12, 0x8a, 0xfe, 0x43, 0x58, 0x01, 0x15, 0xfe, - 0x42, 0x48, 0x8e, 0x01, 0x2c, 0xfe, 0xc0, 0x5a, 0xb0, 0xfe, 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, - 0x4a, 0x46, 0xdc, 0x93, 0x7d, 0x05, 0x10, 0xfe, 0x2e, 0x13, 0x69, 0x54, 0xfe, 0x4d, 0xf4, 0x1c, - 0xfe, 0x1c, 0x13, 0x0e, 0x56, 0x01, 0x8b, 0xaa, 0xfe, 0x40, 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x2c, - 0xfe, 0x00, 0x07, 0x7d, 0x05, 0x10, 0x84, 0x69, 0x8a, 0xfe, 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, - 0x45, 0x58, 0x01, 0x2c, 0xfe, 0x8d, 0x56, 0xb6, 0xfe, 0x80, 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x09, - 0x10, 0x6f, 0x67, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xdb, - 0x37, 0x94, 0xfe, 0x1a, 0x16, 0x01, 0xfe, 0x28, 0x17, 0xfe, 0x0c, 0x13, 0x87, 0x37, 0x67, 0xfe, - 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xba, 0x27, 0xfe, 0x0a, 0x16, 0xfe, 0xe2, 0x10, 0x09, 0x10, - 0x6f, 0x04, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1a, 0xfe, 0x18, 0x58, 0x04, 0xfe, 0x66, 0x01, - 0xfe, 0x19, 0x58, 0x87, 0x1a, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x67, - 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1a, 0x94, 0xfe, 0x64, 0x16, 0xfe, 0xbe, - 0x14, 0x35, 0x03, 0xba, 0x27, 0xfe, 0x3c, 0x16, 0xfe, 0xa4, 0x10, 0x09, 0x10, 0x6f, 0xb6, 0xfe, - 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xdb, 0x42, 0x94, 0xfe, 0x86, 0x16, 0xfe, 0x9c, 0x14, 0xfe, 0x18, - 0x13, 0x87, 0x42, 0x67, 0x1e, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0xa2, 0x07, 0xfe, 0x7f, - 0x00, 0xfe, 0x05, 0x40, 0x03, 0xba, 0x27, 0xfe, 0x7a, 0x16, 0xfe, 0x6c, 0x10, 0x09, 0x10, 0x6f, - 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x87, 0xd9, 0x67, 0x1e, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, - 0xd9, 0x94, 0xfe, 0xc6, 0x16, 0xfe, 0x5c, 0x14, 0x35, 0x03, 0xba, 0x27, 0xfe, 0xb2, 0x16, 0xfe, - 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x6f, 0xfe, 0x18, 0xfe, 0x5d, 0xfe, 0x19, 0xfe, 0x5e, 0xc8, - 0xdb, 0x45, 0x94, 0xfe, 0xec, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x87, 0x45, 0x4e, 0xfe, - 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, - 0x00, 0x64, 0x2f, 0x03, 0x64, 0x2f, 0xfe, 0x12, 0x45, 0x27, 0xfe, 0xdc, 0x16, 0x17, 0x06, 0x4a, - 0xf4, 0xdd, 0x02, 0x26, 0xfe, 0x39, 0xf0, 0xfe, 0x30, 0x17, 0x2d, 0x03, 0xfe, 0x7e, 0x18, 0x1b, - 0x19, 0x83, 0x08, 0x0d, 0x03, 0x6f, 0x04, 0xdf, 0x1b, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, - 0x1d, 0x0e, 0x1c, 0x01, 0x15, 0x05, 0x10, 0x40, 0x3e, 0xfe, 0x78, 0x14, 0xfe, 0x34, 0x12, 0x50, - 0x86, 0x36, 0x37, 0xbf, 0xfe, 0xe9, 0x13, 0x1d, 0x0e, 0x3d, 0x01, 0x15, 0x05, 0x10, 0x40, 0x3e, - 0xfe, 0x56, 0x14, 0xe1, 0x50, 0x86, 0x36, 0x37, 0xbf, 0xfe, 0xe9, 0x13, 0x09, 0x0c, 0x03, 0xfe, - 0x9c, 0xe7, 0x0c, 0x13, 0xfe, 0x15, 0x00, 0x90, 0x9f, 0x2f, 0x01, 0xea, 0x09, 0x06, 0x03, 0x0a, - 0x41, 0x37, 0x38, 0x08, 0x3d, 0x09, 0x99, 0x01, 0x46, 0x11, 0x47, 0x08, 0x1c, 0x09, 0x43, 0x01, - 0x7b, 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x65, 0xf7, 0x31, 0x76, 0xfe, 0x48, - 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x03, 0x21, 0xbe, 0x52, 0x16, 0xbe, 0x03, 0x0e, 0xc0, 0x01, 0x15, - 0xe6, 0x0e, 0x79, 0x01, 0x15, 0xfe, 0x49, 0x44, 0x27, 0xfe, 0x26, 0x18, 0x0e, 0x1c, 0x01, 0x15, - 0x05, 0x10, 0x40, 0x0e, 0x56, 0x01, 0xab, 0x0e, 0x79, 0x01, 0x15, 0x52, 0x7d, 0x03, 0xfe, 0x40, - 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x21, 0x3c, 0x05, 0x10, 0xfe, 0x52, 0x12, 0x3e, 0x05, - 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0xd4, 0xfe, 0xe2, - 0x08, 0x52, 0x3e, 0x3f, 0x05, 0x76, 0xa5, 0xfe, 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7, 0x10, - 0xfe, 0xc4, 0x48, 0x08, 0x2a, 0x09, 0x3c, 0xfe, 0x40, 0x5f, 0x1d, 0x01, 0x46, 0x11, 0xfe, 0xdd, - 0x00, 0xfe, 0x14, 0x46, 0x08, 0x2a, 0x09, 0x3c, 0x01, 0x46, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x40, - 0x4a, 0x6a, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, 0xfe, 0x82, 0x48, 0xfe, 0x04, 0x17, 0x03, 0xeb, - 0x19, 0x74, 0xfe, 0xae, 0x18, 0x04, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xeb, - 0xcc, 0x74, 0xfe, 0xc0, 0x18, 0x04, 0xfe, 0x92, 0x00, 0xc7, 0x1e, 0xd8, 0xeb, 0xfe, 0x0b, 0x00, - 0x74, 0xfe, 0xd2, 0x18, 0x04, 0xfe, 0x94, 0x00, 0xc7, 0x1a, 0xfe, 0x08, 0x10, 0x04, 0xfe, 0x96, - 0x00, 0xc7, 0x85, 0xfe, 0x4e, 0x45, 0xd1, 0xfe, 0x0a, 0x45, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, - 0x10, 0x1b, 0x6c, 0x03, 0x05, 0x80, 0xfe, 0x5a, 0xf0, 0xfe, 0xfe, 0x18, 0x20, 0xfe, 0x09, 0x00, - 0xfe, 0x34, 0x10, 0x05, 0x1e, 0xfe, 0x5a, 0xf0, 0xfe, 0x0c, 0x19, 0x20, 0xcd, 0xfe, 0x26, 0x10, - 0x05, 0x19, 0x83, 0x20, 0x85, 0xd8, 0x05, 0x0c, 0x83, 0x20, 0x88, 0xfe, 0x0e, 0x10, 0x05, 0x06, - 0x83, 0x20, 0x55, 0xc6, 0xaf, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x44, 0x2e, 0xfe, 0x3c, 0x19, - 0x04, 0x6e, 0xb0, 0x03, 0x22, 0xfe, 0x54, 0x19, 0xfe, 0x14, 0xf0, 0x0b, 0x2e, 0xfe, 0x50, 0x19, - 0x03, 0xff, 0x15, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc, 0x01, 0x00, 0x48, 0xe4, + 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, + 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6, + 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00, 0x00, 0xec, 0x85, 0xf0, + 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, + 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80, + 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, + 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, + 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54, + 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00, 0x3e, 0x00, 0x80, 0x00, + 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, + 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55, + 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0, 0x03, 0xf7, 0x06, 0xf7, + 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, + 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0, + 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, + 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, + 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0, + 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, + 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, + 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15, + 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, + 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, + 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, + 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x9e, 0x00, 0xa8, 0x00, + 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, + 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08, + 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x06, 0x12, + 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, + 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47, + 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55, 0x14, 0x56, 0x77, 0x57, + 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, + 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24, + 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, + 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xcf, + 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, + 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b, 0x02, 0xfe, 0xd4, 0x0c, + 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, + 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02, + 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02, 0xfe, 0x46, 0xf0, 0xfe, + 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, + 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18, + 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, + 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, + 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd, + 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x17, 0x06, + 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, + 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f, + 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe, 0x69, 0x10, 0x17, 0x06, + 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, + 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40, + 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0x99, 0x01, + 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, + 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b, + 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0, 0xfe, 0x56, 0x03, 0xfe, + 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, + 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04, + 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40, 0x01, 0x0e, 0xac, 0x75, + 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, + 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4, + 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe, 0x0a, 0xf0, 0xfe, 0x7a, + 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, + 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c, + 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3, 0x0a, 0xca, 0x01, 0x0e, + 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, + 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f, + 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2b, 0xff, 0x02, + 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, + 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, + 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d, 0xfe, 0x2a, 0x13, 0x2f, + 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, + 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12, + 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, + 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, + 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, + 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a, 0xfe, 0x70, 0x12, 0x49, + 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, + 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12, + 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05, 0x11, 0xfe, 0xe3, 0x00, + 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, + 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08, + 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01, 0x86, 0x24, 0x06, 0x12, + 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, + 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe, + 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13, 0x47, 0x01, 0xa7, 0x26, + 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, + 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c, + 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x14, + 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, + 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04, + 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68, 0x06, 0x11, 0x9a, 0x01, + 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, + 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, + 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07, 0x8d, 0x81, 0x02, 0x22, + 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, + 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32, + 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15, 0xfe, 0x1b, 0x00, 0x01, + 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, + 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d, + 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, + 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, + 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02, + 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x77, 0xfe, 0xca, + 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, + 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1, + 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f, 0x40, 0x12, 0x58, 0x01, + 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, + 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, + 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a, 0xfe, 0x2a, 0x12, 0xfe, + 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, + 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe, + 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x39, 0x18, 0x3a, + 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, + 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80, + 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x7a, 0x08, 0x8d, + 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, + 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c, + 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe, 0x52, 0x12, 0xfe, 0x2c, + 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, + 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe, + 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xb5, 0xfe, + 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, + 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33, + 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a, 0xfe, 0x74, 0x18, 0x1c, + 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, + 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe, + 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc, 0xfe, 0x83, 0x80, 0xfe, + 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, + 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf, + 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e, 0x79, 0x56, 0x68, 0x57, + 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, + 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39, + 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x10, 0x58, 0xfe, + 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, + 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe, + 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08, 0x11, 0x9b, 0x09, 0x04, + 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, + 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12, + 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9, 0x14, 0x7a, 0x01, 0x33, + 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, + 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10, + 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x84, 0x05, 0xcb, 0x1c, + 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, + 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca, + 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe, 0x22, 0x00, 0x02, 0x5a, + 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, + 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10, + 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00, 0x2a, 0x13, 0xfe, 0x4e, + 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, + 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48, + 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xdb, 0x10, 0x11, 0xfe, + 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, + 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42, + 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c, 0x09, 0x04, 0x0b, 0xfe, + 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, + 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, + 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x02, 0x29, + 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, + 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe, + 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01, 0xe8, 0x59, 0x11, 0x2d, + 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, + 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe, + 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, + 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, + 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00, + 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa, 0xab, 0x70, 0x05, 0x6b, + 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, + 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01, + 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e, 0x1d, 0xfe, 0xce, 0x45, + 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, + 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d, + 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, + 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, + 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e, + 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12, 0xce, 0x1e, 0x2d, 0x47, + 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, + 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02, + 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, + 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, + 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01, + 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, + 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, + 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24, + 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, + 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, + 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04, + 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xe1, + 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, + 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d, + 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01, 0xe8, 0x11, 0xfe, 0xe9, + 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, + 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe, + 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, 0x40, 0x12, 0x20, 0x63, + 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, + 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe, + 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x24, 0x69, 0x12, 0xc9, + 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, + 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe, + 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c, 0x46, 0x1e, 0x20, 0xed, + 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, + 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d, + 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46, 0xfa, 0xef, 0xfe, 0x42, + 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, + 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, + 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e, 0x10, 0x07, 0x7e, 0x45, + 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, + 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe, + 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b, 0xfe, 0x48, 0x12, 0x07, + 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, + 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe, + 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b, 0x01, 0x08, 0x8c, 0x43, + 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, + 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04, + 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe, 0xc6, 0x10, 0x1e, 0x58, + 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, + 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1, + 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0xfe, + 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, + 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1, + 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e, 0x58, 0xfe, 0x1f, 0x40, + 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, + 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39, + 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06, 0x12, 0xcd, 0x02, 0x5b, + 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, + 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe, + 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, + 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, + 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01, + 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44, 0x01, 0x08, 0x1f, 0xa2, + 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, + 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda, + 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1, 0x05, 0xc6, 0x28, 0x84, + 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, + 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02, + 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06, 0x21, 0x44, 0x01, 0xfe, + 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, + 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05, + 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xd8, 0x14, 0x02, 0x5c, + 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, + 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01, + 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0xfe, 0xff, 0x7f, + 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, + 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, + 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58, 0x03, 0x0a, 0x50, 0x01, + 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, + 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27, + 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, + 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, + 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, + 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe, 0xcc, 0x12, 0x49, 0x04, + 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, + 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83, + 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c, 0x13, 0x06, 0xfe, 0x56, + 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, + 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4, + 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90, 0x01, 0xba, 0xfe, 0x4e, + 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, + 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c, + 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba, 0xfe, 0x9c, 0x14, 0xb7, + 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, + 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe, + 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x0b, 0x01, + 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, + 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08, + 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89, 0x4a, 0x01, 0x08, 0x03, + 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, + 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe, + 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd, 0x01, 0x43, 0x1e, 0xcd, + 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, + 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88, + 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3, 0x88, 0x03, 0x0a, 0x42, + 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, + 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17, + 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, + 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, + 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10, + 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, 0x05, 0xfe, 0x66, 0x01, + 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, + 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6, + 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17, 0x10, 0x71, 0xfe, 0x83, + 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, + 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, + 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71, 0xfe, 0x30, 0xbc, 0xfe, + 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, + 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02, + 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc, 0xfe, 0x1d, 0xf7, 0x4f, + 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, + 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63, + 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14, 0x06, 0x37, 0x95, 0xa9, + 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, + 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c, + 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x3c, 0x8a, 0x0a, + 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, + 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f, + 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xf6, 0xfe, 0xd6, 0xf0, + 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, + 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f, + 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68, 0xc8, 0xfe, 0x48, 0x55, + 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, + 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42, + 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01, 0x0e, 0x73, 0x75, 0x03, + 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, + 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b, + 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05, 0xfe, 0x94, 0x00, 0xfe, + 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, + 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe, + 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1b, 0xfe, 0x5a, + 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, + 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14, + 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9, 0x03, 0x25, 0xfe, 0xca, + 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00, }; STATIC unsigned short _adv_asc3550_size = - sizeof(_adv_asc3550_buf); /* 0x13E5 */ + sizeof(_adv_asc3550_buf); /* 0x13AD */ STATIC ADV_DCNT _adv_asc3550_chksum = - 0x04FFFF0E; /* Expanded checksum. */ + 0x04D52DDDUL; /* Expanded little-endian checksum. */ +/* Microcode buffer is kept after initialization for error recovery. */ STATIC unsigned char _adv_asc38C0800_buf[] = { - 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x00, 0xfc, 0x48, 0xe4, 0x01, 0x00, 0x18, 0xe4, - 0x00, 0xf6, 0x01, 0xf6, 0x18, 0x80, 0x02, 0x00, 0x40, 0x1a, 0x00, 0xfa, 0xff, 0xff, 0x03, 0xf6, - 0xff, 0x00, 0x82, 0xe7, 0x01, 0xfa, 0x9e, 0xe7, 0x09, 0xe7, 0x1a, 0x0f, 0x00, 0xea, 0x01, 0xe6, - 0x03, 0x00, 0x55, 0xf0, 0x18, 0xf4, 0x1e, 0xf0, 0x3e, 0x57, 0x04, 0x00, 0x3e, 0x01, 0x85, 0xf0, - 0x00, 0xe6, 0x03, 0xfc, 0x08, 0x00, 0x2c, 0x1a, 0x32, 0xf0, 0x86, 0xf0, 0xbe, 0x0d, 0xd4, 0x01, - 0xd5, 0xf0, 0x00, 0xec, 0x01, 0xfc, 0x38, 0x54, 0x98, 0x57, 0xbc, 0x00, 0x0c, 0x1c, 0xb1, 0xf0, - 0x3c, 0x00, 0xb4, 0x00, 0xb8, 0x0d, 0x00, 0x57, 0x01, 0xf0, 0x02, 0x13, 0x02, 0xfc, 0x03, 0xe6, - 0x10, 0x00, 0x18, 0x40, 0x3e, 0x1c, 0x44, 0x13, 0x6c, 0x01, 0x6e, 0x01, 0xbd, 0x00, 0xe0, 0x00, - 0x02, 0x80, 0x30, 0xe4, 0x3e, 0x00, 0x74, 0x01, 0x76, 0x01, 0x7c, 0x16, 0x80, 0x00, 0xb9, 0x54, - 0xbb, 0x00, 0xee, 0x13, 0x00, 0x4e, 0x01, 0x01, 0x01, 0xea, 0x02, 0x48, 0x02, 0xfa, 0x04, 0x12, - 0x08, 0x12, 0x3c, 0x56, 0x4e, 0x01, 0x5d, 0xf0, 0x7a, 0x01, 0x7e, 0x10, 0xb6, 0x00, 0xc2, 0x10, - 0xee, 0x08, 0x00, 0x80, 0x05, 0xfc, 0x10, 0x44, 0x24, 0x01, 0x28, 0x01, 0x32, 0x00, 0x3c, 0x01, - 0x40, 0x00, 0x4b, 0xe4, 0x4b, 0xf4, 0x4c, 0x1c, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, - 0x78, 0x01, 0x7c, 0x01, 0xbb, 0x55, 0xc2, 0x0d, 0x00, 0x01, 0x02, 0xee, 0x03, 0x58, 0x03, 0xf7, - 0x03, 0xfa, 0x04, 0x80, 0x08, 0x44, 0x09, 0xf0, 0x0f, 0x00, 0x1b, 0x80, 0x20, 0x01, 0x38, 0x1c, - 0x4e, 0x1c, 0x5b, 0xf0, 0x62, 0x0a, 0xaa, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc0, 0x15, 0xcc, 0x10, - 0x00, 0x4c, 0x00, 0xdc, 0x02, 0x4a, 0x04, 0xfc, 0x05, 0x00, 0x05, 0xf0, 0x05, 0xf8, 0x06, 0x13, - 0x06, 0xf7, 0x08, 0x13, 0x0a, 0x10, 0x0c, 0x00, 0x0e, 0x47, 0x0e, 0xf7, 0x10, 0x0f, 0x20, 0x00, - 0x20, 0x16, 0x2a, 0x01, 0x32, 0x1c, 0x36, 0x00, 0x42, 0x54, 0x44, 0x55, 0x45, 0x5a, 0x52, 0x0c, - 0x59, 0xf0, 0x5c, 0xf0, 0x69, 0x08, 0x6e, 0x0b, 0x83, 0x59, 0xb8, 0xf0, 0xbd, 0x56, 0xcc, 0x18, - 0xce, 0x10, 0xd8, 0x18, 0xf0, 0x00, 0x01, 0x48, 0x04, 0x10, 0x04, 0xea, 0x04, 0xf6, 0x05, 0x80, - 0x05, 0xe6, 0x06, 0x00, 0x06, 0x0f, 0x06, 0x12, 0x0b, 0xf0, 0x0c, 0x10, 0x0c, 0xf0, 0x10, 0x13, - 0x12, 0x10, 0x19, 0x00, 0x19, 0xe4, 0x30, 0x1c, 0x33, 0x00, 0x34, 0x00, 0x38, 0x44, 0x40, 0x5c, - 0x4a, 0xe4, 0x62, 0x1a, 0x68, 0x08, 0x68, 0x54, 0x6c, 0x15, 0x70, 0x15, 0x83, 0x55, 0x83, 0x5a, - 0x91, 0x44, 0xa4, 0x00, 0xac, 0x13, 0xb0, 0x57, 0xb5, 0x00, 0xb8, 0x17, 0xba, 0x00, 0xce, 0x45, - 0xd0, 0x00, 0xe1, 0x00, 0xe5, 0x55, 0xe7, 0x00, 0x00, 0x54, 0x01, 0x58, 0x02, 0x10, 0x02, 0xe6, - 0x03, 0xa1, 0x04, 0x13, 0x06, 0x83, 0x06, 0xf0, 0x07, 0x00, 0x0a, 0x00, 0x0a, 0x12, 0x0a, 0xf0, - 0x0c, 0x12, 0x0c, 0x13, 0x0c, 0x90, 0x0e, 0x13, 0x10, 0x04, 0x10, 0x10, 0x12, 0x1c, 0x19, 0x81, - 0x1a, 0x10, 0x1c, 0x00, 0x1c, 0x12, 0x1d, 0xf7, 0x1e, 0x13, 0x20, 0x1c, 0x20, 0xe7, 0x22, 0x01, - 0x26, 0x01, 0x2a, 0x12, 0x2c, 0x0f, 0x30, 0xe7, 0x32, 0x15, 0x34, 0x1c, 0x36, 0x1c, 0x38, 0x12, - 0x3a, 0x55, 0x3f, 0x00, 0x41, 0x58, 0x43, 0x48, 0x46, 0x1c, 0x4e, 0xe4, 0x76, 0x02, 0x77, 0x57, - 0x78, 0x03, 0x89, 0x48, 0x8e, 0x90, 0x98, 0x80, 0x99, 0x00, 0xfe, 0x9c, 0xf0, 0x27, 0x02, 0xfe, - 0xe0, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xfe, 0xc6, 0x01, 0xfe, 0x56, 0x1a, 0x00, 0xfe, 0xc4, 0x01, - 0xfe, 0x84, 0x01, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x6a, 0x13, 0xfe, 0x05, 0x05, 0xff, 0x40, 0x00, - 0x00, 0x0e, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x10, 0xff, 0xff, 0xff, 0x1f, - 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, - 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x2e, 0x88, 0x0b, 0x01, 0xfe, 0xca, - 0x0f, 0xfe, 0x04, 0xf7, 0xfe, 0xc4, 0x01, 0x88, 0x0b, 0x1c, 0x2e, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, - 0x01, 0xfe, 0x20, 0xf0, 0xdc, 0x04, 0x5f, 0x4f, 0x02, 0xfe, 0xfc, 0x0d, 0x01, 0xfe, 0x5c, 0x0e, - 0xfe, 0xe9, 0x12, 0x02, 0xfe, 0x08, 0x03, 0xfe, 0x28, 0x1c, 0x04, 0xfe, 0xa6, 0x00, 0xfe, 0xdd, - 0x12, 0x47, 0x12, 0xfe, 0xa6, 0x00, 0xcd, 0xfe, 0x48, 0xf0, 0xfe, 0x80, 0x02, 0xfe, 0x49, 0xf0, - 0xfe, 0x9a, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xb8, 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x4a, 0x02, 0xfe, - 0x47, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x3e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x42, - 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x46, 0x02, 0x09, 0x0b, 0xa4, 0x09, 0x06, 0x12, 0xc1, 0x02, 0x27, - 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xfe, 0xed, 0x10, 0xfe, 0x1e, 0x1c, 0xfe, - 0xe9, 0x10, 0x01, 0xfe, 0x2c, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xfe, 0xa8, 0x00, 0x0f, - 0x7c, 0x01, 0xaa, 0x02, 0x27, 0x17, 0x5e, 0x4c, 0xc4, 0x01, 0xfe, 0x40, 0x10, 0x0f, 0x7c, 0x01, - 0x8e, 0xfe, 0xbd, 0x10, 0x0f, 0x7c, 0x01, 0x8e, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, - 0x1c, 0x09, 0x06, 0x12, 0xc1, 0x2e, 0x1b, 0x27, 0xfe, 0x3d, 0xf0, 0xfe, 0xfc, 0x01, 0x28, 0xfe, - 0x8e, 0x02, 0xfe, 0x5a, 0x1c, 0xde, 0xfe, 0x14, 0x1c, 0x17, 0xfe, 0x30, 0x00, 0x4c, 0xc4, 0x01, - 0xfe, 0x30, 0x10, 0x09, 0x06, 0x12, 0xc1, 0x02, 0xfe, 0xc6, 0x01, 0x29, 0x2d, 0x05, 0x10, 0x35, - 0xfe, 0x69, 0x10, 0x09, 0x06, 0x12, 0xc1, 0xfe, 0x04, 0xec, 0x2d, 0x08, 0x2d, 0x09, 0x3e, 0x1c, - 0x01, 0x45, 0x82, 0xfe, 0x05, 0xf6, 0xfe, 0xa8, 0x00, 0x01, 0xfe, 0x56, 0x17, 0x0a, 0x41, 0x8f, - 0x39, 0x11, 0x48, 0x1c, 0xd2, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x90, 0x02, 0x27, 0x0f, 0x3f, 0x01, - 0x15, 0x05, 0x10, 0xdb, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0xfe, 0x28, 0x10, 0x0f, 0xc8, 0x01, - 0x15, 0xf2, 0x0f, 0x7d, 0x01, 0x15, 0xfe, 0x49, 0x54, 0x79, 0xfe, 0x16, 0x03, 0x08, 0x1e, 0x09, - 0x52, 0x01, 0x90, 0x02, 0x27, 0x2e, 0x82, 0xfe, 0x02, 0xe8, 0x31, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, - 0x43, 0xf7, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xdc, 0xfe, 0x40, 0x1c, 0x1b, 0xf8, 0xfe, 0x26, - 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x62, 0x03, 0xfe, 0x11, 0xf0, 0xdc, 0xfe, 0x0e, - 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x82, 0x03, 0xf4, 0x13, 0xfe, 0x11, 0x00, 0x02, 0x6b, 0x2e, 0xfe, - 0x48, 0x1c, 0xf4, 0x1b, 0xf8, 0x34, 0xf8, 0xfe, 0x82, 0xf0, 0xfe, 0x88, 0x03, 0x2b, 0x29, 0xc6, - 0x72, 0x16, 0xc6, 0x0f, 0x7d, 0x01, 0x15, 0x72, 0x80, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x45, 0x11, - 0x3f, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x90, 0xfe, 0x9c, 0x32, 0x11, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, - 0xce, 0x03, 0x1b, 0x32, 0x1f, 0xfe, 0xde, 0x03, 0x01, 0x55, 0xd3, 0xfe, 0xee, 0x03, 0x73, 0x97, - 0xd7, 0xfe, 0xae, 0x06, 0x02, 0x26, 0x04, 0x7c, 0x2c, 0x19, 0xfe, 0x20, 0x05, 0x17, 0x8b, 0x01, - 0x3b, 0x01, 0x9f, 0x01, 0xa1, 0x34, 0xfe, 0x60, 0x02, 0x02, 0xf6, 0xf4, 0x2e, 0x88, 0x18, 0xfe, - 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xf7, 0xfe, 0x48, 0x1c, 0x92, 0x01, 0xfe, 0x9c, 0x13, 0xb3, 0xfe, - 0x96, 0xf0, 0xfe, 0x28, 0x04, 0x2f, 0xfe, 0x2c, 0x04, 0x34, 0x27, 0x0f, 0x3f, 0x01, 0x15, 0x05, - 0x10, 0x19, 0xfe, 0x0c, 0x05, 0x4d, 0x7a, 0xa5, 0x31, 0x86, 0x76, 0x1b, 0x32, 0x1f, 0x26, 0x04, - 0x7c, 0x2c, 0xfe, 0x10, 0x12, 0x17, 0x8b, 0x01, 0x3b, 0x34, 0xfe, 0x60, 0x02, 0x02, 0xf6, 0x21, - 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x5e, 0x12, 0x0a, 0x07, 0x06, 0xfe, 0x56, 0x12, 0x24, - 0x23, 0x9a, 0x01, 0x0c, 0x86, 0x76, 0x1f, 0xfe, 0xdc, 0x04, 0x24, 0x23, 0x9a, 0x01, 0x0c, 0x1f, - 0x26, 0x24, 0x23, 0xba, 0xfe, 0x4c, 0x44, 0xfe, 0x32, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x08, 0xfe, - 0x93, 0x00, 0xfe, 0x4c, 0x54, 0x79, 0xfe, 0x0c, 0x05, 0x82, 0xa5, 0x31, 0xfe, 0x06, 0x80, 0xfe, - 0x48, 0x47, 0xfe, 0x48, 0x13, 0x40, 0x05, 0xfe, 0xcc, 0x00, 0xfe, 0x40, 0x13, 0x0a, 0x07, 0x06, - 0xef, 0xfe, 0x06, 0x10, 0x24, 0x23, 0xba, 0x0a, 0x07, 0x38, 0xe2, 0x17, 0xa9, 0x0a, 0x07, 0x06, - 0x4f, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x3b, 0x34, 0xfe, 0xa0, 0x0d, 0x02, 0x26, 0x3a, 0x11, 0xfe, - 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xb7, 0x03, 0x17, 0xa9, 0x01, 0x3b, 0x34, 0x27, 0x1b, 0x27, 0x02, - 0xfe, 0x14, 0x05, 0xfe, 0x42, 0x5b, 0x88, 0x18, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xf7, 0x17, - 0x46, 0xfe, 0x07, 0x80, 0xfe, 0x31, 0x44, 0x0a, 0x07, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, - 0x05, 0x18, 0xfe, 0x70, 0x12, 0x75, 0x07, 0x06, 0xfe, 0x60, 0x13, 0x04, 0xfe, 0xa2, 0x00, 0x2c, - 0x19, 0xfe, 0xac, 0x05, 0xfe, 0x31, 0xe4, 0x60, 0x75, 0x07, 0x0b, 0xfe, 0x4a, 0x13, 0x04, 0xfe, - 0xa0, 0x00, 0x2c, 0xfe, 0x42, 0x12, 0x63, 0x2f, 0xfe, 0x6c, 0x05, 0x1b, 0x32, 0xf9, 0x01, 0x0c, - 0x25, 0xfe, 0xc4, 0x05, 0x11, 0xfe, 0xe3, 0x00, 0x2b, 0x75, 0xfe, 0x4a, 0xf0, 0xfe, 0x96, 0x05, - 0xfe, 0x49, 0xf0, 0xfe, 0x90, 0x05, 0xad, 0x20, 0xfe, 0x21, 0x00, 0x8a, 0x20, 0xfe, 0x22, 0x00, - 0xa4, 0x20, 0x8f, 0xfe, 0x09, 0x48, 0x01, 0x0c, 0x25, 0xfe, 0xc4, 0x05, 0xfe, 0xe2, 0x08, 0x75, - 0x07, 0xe1, 0x4f, 0x01, 0xc2, 0x20, 0x06, 0x16, 0xe8, 0x4c, 0xfe, 0x27, 0x01, 0x0a, 0x07, 0x38, - 0xe9, 0x47, 0x01, 0xbd, 0x17, 0xa9, 0x0a, 0x07, 0x06, 0x4f, 0x17, 0xfe, 0x0d, 0x00, 0x01, 0x3b, - 0x01, 0x9f, 0x01, 0xa1, 0x34, 0xfe, 0xa0, 0x0d, 0x02, 0x26, 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0xfe, - 0x3e, 0x12, 0x04, 0x5c, 0x2c, 0xfe, 0x36, 0x13, 0x47, 0x01, 0xbd, 0x25, 0xfe, 0x3c, 0x06, 0x0f, - 0x06, 0x75, 0x07, 0x22, 0xfe, 0x02, 0x12, 0x6a, 0x01, 0xfe, 0x06, 0x15, 0x1f, 0xfe, 0x32, 0x06, - 0x11, 0xc9, 0x01, 0x55, 0x11, 0xfe, 0xe5, 0x00, 0x04, 0x5c, 0xc3, 0x0d, 0x5c, 0x04, 0xfe, 0x9e, - 0x00, 0x2c, 0xfe, 0x62, 0x12, 0x04, 0x56, 0x2c, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x7e, 0x19, 0x01, - 0xfe, 0xe8, 0x19, 0xf3, 0xa8, 0xf1, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0x59, - 0xd1, 0xa8, 0x74, 0x47, 0x01, 0xbd, 0x25, 0xfe, 0xa6, 0x06, 0x75, 0x07, 0x1d, 0xab, 0x9e, 0x0f, - 0x5e, 0x01, 0xfe, 0x34, 0x15, 0x1f, 0xfe, 0x9c, 0x06, 0x11, 0xc9, 0x01, 0x55, 0x11, 0xfe, 0xe5, - 0x00, 0x04, 0x56, 0xc3, 0x0d, 0x56, 0x09, 0x06, 0x01, 0xbd, 0xfe, 0x9c, 0x32, 0x78, 0x92, 0x01, - 0xfe, 0x9c, 0x13, 0xb3, 0x11, 0xfe, 0xe2, 0x00, 0x2f, 0xfe, 0xbe, 0x06, 0x1b, 0x32, 0xd7, 0xfe, - 0xda, 0x06, 0x85, 0xfe, 0x78, 0x07, 0xd3, 0xfe, 0x80, 0x07, 0x73, 0x97, 0x02, 0x26, 0x0a, 0x07, - 0x0b, 0xfe, 0x2e, 0x12, 0x14, 0x18, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, - 0x14, 0x00, 0x01, 0x0c, 0xfe, 0x99, 0xa4, 0x01, 0x0c, 0x14, 0x00, 0x02, 0xfe, 0x50, 0x08, 0x71, - 0x07, 0x1d, 0xef, 0x0a, 0x07, 0x1d, 0xfe, 0x30, 0x13, 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x0c, 0x14, - 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x00, 0x01, 0x0c, 0x14, 0x06, 0x01, 0x0c, 0x14, - 0x00, 0x02, 0xfe, 0x0a, 0x0c, 0x6a, 0xfe, 0x9a, 0x81, 0x6f, 0x8f, 0xfe, 0x09, 0x6f, 0xfe, 0x93, - 0x45, 0x19, 0xfe, 0x88, 0x07, 0x2f, 0xfe, 0x60, 0x07, 0x1b, 0x32, 0xd7, 0xfe, 0x58, 0x07, 0x73, - 0x97, 0x85, 0xfe, 0x78, 0x07, 0x02, 0x26, 0x01, 0x55, 0x02, 0xfe, 0xbe, 0x06, 0x14, 0x22, 0x02, - 0xfe, 0xbe, 0x06, 0xfe, 0x9c, 0xf7, 0xfe, 0xf0, 0x07, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x53, - 0xfe, 0xd6, 0x07, 0x0d, 0x66, 0x12, 0x67, 0x0a, 0x41, 0x60, 0x39, 0x01, 0xfe, 0x14, 0x19, 0x05, - 0x10, 0x87, 0xfe, 0x83, 0xe7, 0xfe, 0x95, 0x00, 0x8a, 0xfe, 0x03, 0x40, 0x0a, 0x41, 0x46, 0x39, - 0x01, 0xc5, 0xb6, 0xfe, 0x1f, 0x40, 0x16, 0x68, 0x01, 0xfe, 0xbe, 0x13, 0xfe, 0x08, 0x50, 0xfe, - 0x8a, 0x50, 0xfe, 0x34, 0x51, 0xfe, 0xb6, 0x51, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0d, 0x64, - 0x12, 0x65, 0xda, 0xfa, 0x0d, 0x3c, 0x12, 0x3d, 0xfe, 0x60, 0x10, 0x0a, 0x07, 0x60, 0xe9, 0xfe, - 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0d, 0x66, 0x12, 0x67, 0x0a, 0x07, 0x46, 0xd1, 0x01, 0xc5, 0xfe, - 0x1f, 0x80, 0x16, 0x68, 0xfe, 0x34, 0x90, 0xfe, 0xb6, 0x90, 0x0d, 0x43, 0x12, 0x44, 0xfe, 0x08, - 0x90, 0xfe, 0x8a, 0x90, 0x0d, 0x64, 0x12, 0x65, 0xa7, 0x07, 0x46, 0xdb, 0xda, 0xfa, 0x0d, 0x3c, - 0x12, 0x3d, 0xad, 0xfe, 0x28, 0x90, 0xfe, 0xaa, 0x90, 0x0d, 0x3c, 0x12, 0x3d, 0x0d, 0x30, 0x12, - 0x42, 0x2b, 0x0d, 0x54, 0x0d, 0x69, 0x0a, 0x41, 0x22, 0x39, 0x2e, 0x08, 0x84, 0x2f, 0xfe, 0x70, - 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x84, 0x08, 0xa3, 0x19, 0x32, 0x2e, 0x5b, 0xfe, 0xed, 0x10, 0xac, - 0xfe, 0xa8, 0x08, 0xae, 0xfe, 0xc4, 0x08, 0x85, 0xfe, 0x9c, 0x08, 0xd3, 0xfe, 0xa2, 0x08, 0x73, - 0x97, 0x02, 0x26, 0x01, 0x55, 0xfe, 0xc9, 0x10, 0x14, 0x22, 0xfe, 0xc9, 0x10, 0x71, 0x07, 0x06, - 0xfe, 0x10, 0x12, 0x71, 0x07, 0x0b, 0x50, 0x0a, 0x07, 0x0b, 0xfe, 0xa6, 0x12, 0xfe, 0x2e, 0x1c, - 0xb0, 0x71, 0x07, 0x06, 0x50, 0x71, 0x07, 0x0b, 0xfe, 0x92, 0x12, 0xfe, 0x2c, 0x1c, 0xa7, 0x07, - 0x46, 0xaf, 0xa7, 0x41, 0x46, 0xfe, 0x05, 0x40, 0xda, 0xfa, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, - 0xfe, 0xaa, 0xf0, 0xfe, 0xf6, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x24, 0x09, 0x02, 0xfe, 0x02, 0x0a, - 0xfe, 0xb7, 0xf0, 0xfe, 0x20, 0x09, 0xfe, 0x02, 0xf6, 0x1d, 0x6a, 0xfe, 0x70, 0x18, 0xfe, 0xf1, - 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, - 0xfe, 0x95, 0x59, 0x1b, 0x9b, 0xfe, 0x8c, 0xf0, 0xfe, 0x20, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x14, - 0x09, 0xed, 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x30, 0x09, 0x02, 0xfe, 0x3c, 0x0b, 0xee, - 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x9b, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xfe, 0xe2, 0xcd, - 0xfe, 0xd2, 0xf0, 0x9b, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0x19, 0x9b, 0x04, 0xe7, 0x1a, 0x06, 0x19, - 0x9b, 0xac, 0x58, 0xae, 0x58, 0xed, 0xee, 0xfe, 0x89, 0x10, 0x92, 0x63, 0x3a, 0x17, 0xa9, 0x01, - 0x3b, 0x13, 0xfe, 0x35, 0x00, 0x34, 0x6b, 0x13, 0x93, 0x02, 0x6b, 0xfb, 0xb2, 0x0b, 0xfe, 0x1a, - 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xf0, 0xdf, 0xfe, 0x74, 0x18, - 0x94, 0x95, 0x19, 0xfe, 0xf2, 0x08, 0x02, 0x58, 0x0a, 0x07, 0x60, 0xaf, 0x04, 0x30, 0x2a, 0x42, - 0x0d, 0x43, 0x12, 0x44, 0x83, 0x30, 0x5a, 0x42, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, - 0x54, 0xfe, 0xe5, 0x54, 0x36, 0x43, 0x21, 0x44, 0x04, 0x54, 0x2a, 0x69, 0x94, 0xfe, 0xe3, 0x54, - 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x94, 0xfe, 0xe3, 0x54, 0x95, 0xca, 0x53, 0xfe, 0xf2, 0x08, - 0x02, 0x58, 0xfe, 0x37, 0xf0, 0xfe, 0xfe, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x84, 0x09, 0x02, 0x58, - 0xfb, 0xb2, 0x0b, 0x28, 0xfe, 0x1e, 0x0b, 0x36, 0x54, 0x21, 0x69, 0x53, 0x7a, 0x08, 0xfe, 0xc0, - 0x07, 0x47, 0x62, 0x00, 0xd9, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x30, 0x0a, 0x94, 0x99, - 0xfe, 0x48, 0x0a, 0x36, 0x54, 0x94, 0xfe, 0xe3, 0x54, 0x4e, 0x54, 0x70, 0x69, 0xfe, 0x14, 0x58, - 0xfe, 0x95, 0x58, 0x02, 0x58, 0x36, 0x54, 0x21, 0x69, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xf0, - 0x4e, 0x54, 0x4e, 0x69, 0x02, 0x58, 0x0a, 0x07, 0x60, 0xfe, 0x82, 0x12, 0x0a, 0x07, 0x22, 0xfe, - 0x66, 0x13, 0x29, 0x68, 0x72, 0xd0, 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, - 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6d, 0x31, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x53, 0xfe, 0xfa, - 0x08, 0x04, 0x66, 0x2a, 0x67, 0x0d, 0xb5, 0x12, 0x93, 0x4e, 0x66, 0x70, 0x67, 0x01, 0xc5, 0xb6, - 0x6d, 0x31, 0x16, 0x68, 0x83, 0x30, 0x5a, 0x42, 0x36, 0x43, 0x21, 0x44, 0x95, 0xca, 0xfe, 0x04, - 0xfa, 0x30, 0xfe, 0x05, 0xfa, 0x42, 0x01, 0xfe, 0xbe, 0x13, 0xfe, 0x36, 0x10, 0x2b, 0x0d, 0xb5, - 0x0d, 0x93, 0x36, 0x43, 0x21, 0x44, 0xb0, 0x0a, 0x07, 0x22, 0x19, 0xfe, 0xfa, 0x08, 0x36, 0x3c, - 0x21, 0x3d, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x39, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x10, 0x58, 0xfe, - 0x91, 0x58, 0x4e, 0x54, 0x70, 0x69, 0x02, 0xfe, 0x18, 0x0a, 0x0a, 0x07, 0x22, 0x19, 0xfe, 0xfa, - 0x08, 0x0a, 0x07, 0xfe, 0xf7, 0x00, 0x39, 0xf0, 0xdf, 0x6a, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, - 0xfe, 0xd3, 0x10, 0x40, 0x05, 0xcb, 0x19, 0xfe, 0x2c, 0x09, 0x11, 0xcb, 0xfb, 0xb2, 0x0b, 0xfe, - 0x14, 0x13, 0x04, 0x3c, 0x2a, 0x3d, 0x53, 0xfe, 0x2c, 0x09, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, - 0x02, 0x58, 0x2b, 0x47, 0xfe, 0x19, 0x80, 0xfe, 0xf1, 0x10, 0x0a, 0x07, 0x0b, 0xab, 0xfe, 0x6c, - 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x4e, 0x3c, 0xfe, 0xed, 0x19, 0x70, - 0x3d, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x1a, 0xfe, 0x00, 0xff, 0x35, 0xfe, - 0x74, 0x10, 0xcd, 0xfe, 0xd2, 0xf0, 0xfe, 0xb6, 0x0b, 0xfe, 0x76, 0x18, 0x1a, 0x18, 0xd6, 0x04, - 0xe7, 0x1a, 0x06, 0x89, 0x13, 0xfe, 0x16, 0x00, 0x02, 0x6b, 0xfe, 0xd1, 0xf0, 0xfe, 0xc8, 0x0b, - 0x17, 0x84, 0x01, 0x3b, 0x13, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xce, - 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xda, 0x0b, 0x13, 0xfe, 0x22, 0x00, 0x02, 0x6b, - 0xfe, 0xcb, 0xf0, 0xfe, 0xe6, 0x0b, 0x13, 0xfe, 0x24, 0x00, 0x02, 0x6b, 0xfe, 0xd0, 0xf0, 0xfe, - 0xf0, 0x0b, 0x13, 0xb1, 0xe0, 0xfe, 0xcf, 0xf0, 0xfe, 0xfa, 0x0b, 0x13, 0x8f, 0xdd, 0xfe, 0xcc, - 0xf0, 0xfe, 0x0a, 0x0c, 0xfe, 0x84, 0x80, 0xb2, 0x22, 0x4f, 0x13, 0xfe, 0x12, 0x00, 0x2e, 0x08, - 0x84, 0x2f, 0xfe, 0x10, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x24, 0x0c, 0xa3, 0x19, 0x32, 0x2e, 0x5b, - 0xfe, 0xed, 0x10, 0xac, 0x26, 0xae, 0x26, 0x2e, 0xfe, 0x9c, 0x32, 0x2f, 0xfe, 0x30, 0x0c, 0x1b, - 0x32, 0x85, 0xfe, 0x4c, 0x0c, 0x73, 0x97, 0xac, 0xfe, 0xf0, 0x07, 0xae, 0xfe, 0xf0, 0x07, 0x02, - 0x26, 0x01, 0x55, 0xfe, 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xed, 0xee, 0x92, 0x86, 0x76, 0xfe, - 0x89, 0xf0, 0x26, 0x24, 0x23, 0xfe, 0xe9, 0x09, 0x01, 0x0c, 0x86, 0x76, 0x1f, 0x26, 0x24, 0x23, - 0x9a, 0x34, 0xfe, 0x88, 0x0c, 0x1b, 0x32, 0x02, 0xfe, 0x7c, 0x0c, 0xa3, 0x50, 0x13, 0xfe, 0x42, - 0x00, 0x02, 0x6b, 0xa6, 0x06, 0xfe, 0x81, 0x49, 0xfe, 0xcc, 0x12, 0x0a, 0x07, 0x0b, 0xfe, 0x5a, - 0x13, 0x13, 0x00, 0x61, 0x0b, 0xfe, 0x6a, 0x12, 0x61, 0xfe, 0x28, 0x00, 0x28, 0xfe, 0xce, 0x0d, - 0x0f, 0x7d, 0x01, 0x15, 0x05, 0x00, 0x89, 0x37, 0xfe, 0x28, 0x00, 0x02, 0xfe, 0xce, 0x0d, 0x01, - 0x9f, 0x01, 0xa1, 0x0f, 0xc8, 0x01, 0xfe, 0x24, 0x0f, 0xb9, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, - 0x11, 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x02, 0x27, 0x13, 0xfe, 0x44, 0x00, 0x61, 0x0b, - 0xab, 0x37, 0x0b, 0xfe, 0xc0, 0x10, 0x01, 0xc2, 0x37, 0x0b, 0xfe, 0xb6, 0x10, 0x01, 0xc2, 0xfe, - 0x19, 0x82, 0xfe, 0x34, 0x46, 0xfe, 0x0a, 0x13, 0x37, 0x0b, 0x13, 0xfe, 0x43, 0x00, 0xfe, 0xa2, - 0x10, 0x0a, 0x41, 0x0b, 0x39, 0x01, 0x9f, 0x01, 0xa1, 0xb9, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, - 0x11, 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x88, 0x0b, 0xb9, 0x1c, 0xd2, 0x02, 0xfe, 0x4c, - 0x03, 0x0a, 0x07, 0x0b, 0xd6, 0x37, 0x0b, 0x13, 0x00, 0xfe, 0x54, 0x10, 0x71, 0x07, 0x1d, 0xfe, - 0x50, 0x12, 0x0a, 0x07, 0x1d, 0xfe, 0x48, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x8c, - 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x92, 0x0d, 0x0a, 0x41, 0x1d, 0x39, 0xfe, 0x95, - 0x10, 0x13, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x6a, 0xfe, 0x26, 0x10, 0x13, 0xfe, 0x13, - 0x00, 0xdd, 0x13, 0xfe, 0x47, 0x00, 0x8a, 0x13, 0xfe, 0x41, 0x00, 0xa4, 0x13, 0xfe, 0x24, 0x00, - 0x04, 0x7c, 0x2c, 0x28, 0xf6, 0x6a, 0xfe, 0x04, 0xe6, 0x1d, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, - 0xb9, 0x01, 0xea, 0x02, 0x27, 0xde, 0x17, 0x0b, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0x17, 0xfe, 0x31, - 0x00, 0x4c, 0xc4, 0x01, 0xfe, 0x30, 0x10, 0x02, 0xfe, 0xc6, 0x01, 0x1c, 0xfe, 0x06, 0xec, 0xfe, - 0xb9, 0x00, 0x8c, 0x37, 0x38, 0xc7, 0x35, 0x1c, 0xfe, 0x06, 0xea, 0xfe, 0xb9, 0x00, 0xfe, 0x47, - 0x4b, 0x9e, 0xfe, 0x75, 0x57, 0x04, 0x5f, 0xfe, 0x98, 0x56, 0xfe, 0x28, 0x12, 0x0f, 0x7d, 0xfe, - 0xf4, 0x14, 0x47, 0xf2, 0x0f, 0xc8, 0xfe, 0xea, 0x14, 0xfe, 0x49, 0x54, 0x98, 0xfe, 0x42, 0x0e, - 0x0f, 0x1e, 0xfe, 0xde, 0x14, 0xfe, 0x44, 0x48, 0x02, 0xfe, 0x4c, 0x03, 0x0f, 0x5f, 0xfe, 0xc8, - 0x14, 0x8c, 0x37, 0x38, 0xc7, 0x35, 0x1c, 0xfe, 0xce, 0x47, 0xfe, 0xbd, 0x13, 0x02, 0x27, 0x29, - 0x2d, 0x05, 0x10, 0xfe, 0x78, 0x12, 0x2b, 0x16, 0x5e, 0x16, 0xb4, 0x29, 0x48, 0x47, 0x4c, 0x48, - 0xa3, 0xd9, 0xfe, 0xbc, 0xf0, 0xfe, 0xde, 0x0e, 0x08, 0x06, 0x16, 0x5e, 0x01, 0xfe, 0xe6, 0x16, - 0x04, 0xfe, 0x38, 0x01, 0x2a, 0xfe, 0x3a, 0x01, 0x53, 0xfe, 0xe2, 0x0e, 0x04, 0xfe, 0x38, 0x01, - 0x1a, 0xfe, 0xf0, 0xff, 0x0d, 0xfe, 0x60, 0x01, 0x04, 0xfe, 0x3a, 0x01, 0x0d, 0xfe, 0x62, 0x01, - 0x20, 0x06, 0x16, 0x48, 0xfe, 0x04, 0xec, 0x2d, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x01, 0x45, 0x82, - 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x56, 0x17, 0x11, 0x48, 0xd2, 0x08, 0x06, 0x03, - 0x2b, 0x03, 0x29, 0x5e, 0xfe, 0xf7, 0x12, 0x29, 0xb4, 0x72, 0x16, 0xb4, 0x05, 0x84, 0xfe, 0x93, - 0x13, 0xfe, 0x24, 0x1c, 0x17, 0x18, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0xfe, 0xd9, 0x10, 0x9c, 0xfe, - 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0x9c, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, - 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0x9c, 0x2b, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, - 0x9c, 0x80, 0x03, 0x01, 0xfe, 0x8e, 0x17, 0x40, 0x05, 0x48, 0xfe, 0x0a, 0x13, 0x08, 0x1e, 0x09, - 0x52, 0xdd, 0x01, 0x9f, 0x01, 0xa1, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, 0x11, 0xfe, 0xe9, 0x00, - 0x0a, 0x07, 0x8f, 0xfe, 0x52, 0x13, 0x01, 0xfe, 0x18, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, - 0x0d, 0xfe, 0x64, 0x01, 0xfe, 0x16, 0x90, 0x0d, 0xfe, 0x66, 0x01, 0x0a, 0x07, 0x46, 0xef, 0xfe, - 0x03, 0x80, 0x5b, 0x4d, 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x90, 0xfe, 0x62, - 0x08, 0x72, 0x4d, 0x11, 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x90, 0x6d, 0x31, 0x11, - 0x7b, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x7a, 0x01, 0x7e, 0x03, 0xfe, 0x08, 0x1c, 0x04, 0xfe, 0xac, - 0x00, 0xfe, 0x06, 0x58, 0x04, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x04, 0xfe, 0xb0, 0x00, 0xfe, - 0x08, 0x58, 0x04, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x20, 0x74, 0x16, 0xfe, - 0xb9, 0x00, 0x2b, 0x0d, 0x5c, 0x0d, 0x56, 0x20, 0x10, 0x16, 0x2d, 0x16, 0x3e, 0x51, 0xa6, 0xfe, - 0x93, 0x00, 0x08, 0x2d, 0x09, 0x3e, 0x1c, 0x01, 0x7e, 0x82, 0x11, 0x7b, 0xfe, 0x14, 0x56, 0xfe, - 0xd6, 0xf0, 0x8a, 0xde, 0x92, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x1c, - 0xfe, 0x0c, 0x14, 0x8c, 0xfe, 0x07, 0xe6, 0x38, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, - 0xc2, 0x0f, 0x3f, 0x01, 0x15, 0x05, 0x10, 0xdb, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0xe2, 0xfe, - 0x44, 0x58, 0x4d, 0xfe, 0x01, 0xec, 0xc4, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, - 0xe7, 0x1d, 0xa5, 0x31, 0x01, 0xea, 0xfe, 0xc9, 0x10, 0x03, 0x2e, 0x86, 0x76, 0x24, 0x23, 0xba, - 0x05, 0x1d, 0xfe, 0x48, 0x12, 0x05, 0x0b, 0xfe, 0x4c, 0x12, 0x05, 0x18, 0xfe, 0x30, 0x12, 0x05, - 0xd4, 0x19, 0xfe, 0xd4, 0x11, 0x05, 0xfe, 0x23, 0x00, 0x19, 0xfe, 0xe0, 0x11, 0x05, 0x06, 0x19, - 0xfe, 0x3e, 0x12, 0x05, 0x22, 0xfe, 0x12, 0x12, 0x05, 0x00, 0x19, 0x26, 0x17, 0xd4, 0x01, 0x3b, - 0xce, 0x3a, 0x01, 0x0c, 0x85, 0x55, 0x03, 0x3a, 0x11, 0xfe, 0xcc, 0x00, 0x02, 0x27, 0x3a, 0x40, - 0x05, 0xcb, 0xfe, 0xe3, 0x13, 0x36, 0x3c, 0x21, 0x3d, 0x53, 0xfe, 0x92, 0x11, 0x0a, 0x07, 0x60, - 0xfe, 0x72, 0x12, 0x83, 0x30, 0x5a, 0x42, 0x95, 0xca, 0x98, 0xfe, 0x5c, 0x11, 0x29, 0x68, 0xfe, - 0x26, 0x13, 0x04, 0xb5, 0x2a, 0x93, 0x53, 0xfe, 0xb2, 0x0d, 0x0d, 0x66, 0x12, 0x67, 0x2b, 0x0d, - 0xb5, 0x0d, 0x93, 0x01, 0xc5, 0x20, 0x74, 0x5b, 0x16, 0x68, 0x01, 0xfe, 0xbe, 0x13, 0x83, 0x30, - 0x5a, 0x42, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x30, 0xfe, 0x05, 0xfa, 0x42, - 0xfe, 0x91, 0x10, 0x04, 0x43, 0x2a, 0x44, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0d, 0x43, 0x12, - 0x44, 0xad, 0x83, 0x30, 0x5a, 0x42, 0x95, 0xca, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x00, 0x56, 0xfe, - 0xa1, 0x56, 0x0d, 0x64, 0x12, 0x65, 0x0a, 0x07, 0x60, 0xfe, 0x1e, 0x12, 0x29, 0x68, 0xfe, 0x1f, - 0x40, 0x04, 0x66, 0x2a, 0x67, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x04, 0x43, 0x2a, 0x44, 0xfe, - 0x34, 0x50, 0xfe, 0xb6, 0x50, 0x04, 0x64, 0x2a, 0x65, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x04, - 0x3c, 0x2a, 0x3d, 0xfe, 0x28, 0x50, 0xfe, 0xaa, 0x50, 0x02, 0xa0, 0x20, 0x06, 0x16, 0xfc, 0x02, - 0x7f, 0x3a, 0x01, 0x0c, 0x1f, 0x57, 0x24, 0x23, 0xba, 0x05, 0x06, 0x28, 0x57, 0x40, 0x05, 0xcb, - 0x28, 0x7f, 0x01, 0xfe, 0x9c, 0x13, 0x1a, 0x59, 0x19, 0x57, 0x0a, 0x07, 0x0b, 0xe4, 0x36, 0x3c, - 0x21, 0x3d, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x4e, 0x3c, 0x70, 0x3d, 0xfe, 0x0c, 0x51, - 0xfe, 0x8e, 0x51, 0x02, 0x7f, 0xdf, 0xfe, 0x0a, 0x45, 0xfe, 0x19, 0x41, 0x02, 0x7f, 0x3a, 0x01, - 0x0c, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, 0xfe, 0xe9, 0x09, 0x61, 0x18, 0xfe, 0x94, 0x12, 0x61, - 0x0b, 0x4f, 0x02, 0x57, 0x2f, 0xfe, 0x5e, 0x12, 0x1b, 0x32, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, - 0x9a, 0x05, 0x18, 0x28, 0x57, 0x01, 0x0c, 0x1f, 0xfe, 0xd6, 0x10, 0x24, 0x23, 0xfe, 0xe8, 0x09, - 0x51, 0x04, 0xfe, 0x9c, 0x00, 0x2c, 0x35, 0xfe, 0xbb, 0x45, 0x61, 0x00, 0x50, 0x37, 0x06, 0xa6, - 0x59, 0xfe, 0xc0, 0x14, 0xfe, 0xf8, 0x14, 0xb3, 0x40, 0x05, 0xc9, 0xfe, 0x16, 0x13, 0x04, 0xfe, - 0x9e, 0x00, 0x2c, 0xd6, 0x04, 0x56, 0x2c, 0x35, 0x63, 0x02, 0x7f, 0xfe, 0xc0, 0x5d, 0xfe, 0xe4, - 0x14, 0xfe, 0x03, 0x17, 0x04, 0x5c, 0xc3, 0x0d, 0x5c, 0x63, 0x3a, 0x01, 0x0c, 0x25, 0xa0, 0x01, - 0xfe, 0x06, 0x15, 0x02, 0xa0, 0x2f, 0xfe, 0xe8, 0x12, 0x1b, 0x32, 0x1f, 0x57, 0x24, 0x23, 0x9a, - 0x05, 0x06, 0x28, 0x57, 0xfe, 0xf6, 0x14, 0xfe, 0x42, 0x58, 0xfe, 0x70, 0x14, 0xfe, 0x92, 0x14, - 0xb3, 0xfe, 0x4a, 0xf4, 0x0b, 0x19, 0x57, 0xfe, 0x4a, 0xf4, 0x06, 0xd8, 0x40, 0x05, 0xc9, 0xd1, - 0x02, 0x7f, 0x04, 0x56, 0xc3, 0x0d, 0x56, 0x63, 0x3a, 0x01, 0x0c, 0x25, 0xa0, 0x01, 0xfe, 0x34, - 0x15, 0x02, 0xa0, 0x25, 0xfe, 0x50, 0x13, 0x78, 0xf9, 0x78, 0x03, 0x34, 0xfe, 0x4c, 0x13, 0x73, - 0xfe, 0x4c, 0x13, 0x63, 0x3a, 0x01, 0x0c, 0xfe, 0xe3, 0x10, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, - 0x6e, 0x81, 0x1a, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x6c, 0xff, - 0x02, 0x00, 0x57, 0x6e, 0x81, 0x1a, 0x59, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x08, 0x6c, - 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0x03, 0x08, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x6e, 0x81, 0xfe, - 0x0b, 0x58, 0x03, 0x0f, 0x5c, 0x01, 0x8e, 0x0f, 0x56, 0x01, 0x8e, 0x03, 0xd0, 0x1a, 0x10, 0xff, - 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x22, 0x6e, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, - 0x7d, 0xfe, 0x03, 0x7c, 0x6d, 0x31, 0x0d, 0x64, 0x12, 0x65, 0x4e, 0x43, 0x70, 0x44, 0x03, 0xfe, - 0x62, 0x18, 0xfe, 0x82, 0x5a, 0xfe, 0xe1, 0x1a, 0xbf, 0xfe, 0x02, 0x58, 0x03, 0x01, 0xfe, 0x7e, - 0x19, 0xfe, 0x42, 0x48, 0x6a, 0x51, 0x9e, 0x01, 0x0c, 0x1f, 0xfe, 0xfe, 0x14, 0x24, 0x23, 0xfe, - 0xe9, 0x09, 0xfe, 0xc1, 0x59, 0x01, 0x0c, 0x1f, 0xfe, 0xfe, 0x14, 0x24, 0x23, 0xfe, 0xe8, 0x0a, - 0x04, 0xfe, 0x9e, 0x00, 0x2c, 0xfe, 0xc4, 0x12, 0x2b, 0xb8, 0x1d, 0xe4, 0x61, 0xd5, 0x79, 0xfe, - 0x4c, 0x14, 0x4f, 0x08, 0x06, 0x09, 0xd5, 0xa6, 0xfe, 0x00, 0x10, 0xfe, 0x78, 0x10, 0xff, 0x02, - 0x83, 0x55, 0x8a, 0xff, 0x02, 0x83, 0x55, 0xb8, 0x18, 0xfe, 0x12, 0x13, 0x62, 0xfe, 0x30, 0x00, - 0x98, 0xfe, 0xa6, 0x14, 0x09, 0x8b, 0x08, 0x06, 0xfe, 0x56, 0x10, 0xb8, 0x0b, 0xfe, 0x16, 0x13, - 0x62, 0xfe, 0x64, 0x00, 0x98, 0xfe, 0xa6, 0x14, 0x0f, 0xfe, 0x64, 0x00, 0x09, 0xb1, 0x08, 0x06, - 0xfe, 0x28, 0x10, 0xb8, 0x06, 0xfe, 0x60, 0x13, 0x62, 0xfe, 0xc8, 0x00, 0x98, 0xfe, 0xa6, 0x14, - 0x0f, 0xfe, 0xc8, 0x00, 0x09, 0x5e, 0x08, 0x06, 0xad, 0x62, 0xfe, 0x90, 0x01, 0x99, 0xfe, 0xb2, - 0x14, 0x9e, 0xb0, 0xfe, 0x43, 0xf4, 0xb4, 0xfe, 0x56, 0xf0, 0xfe, 0xc4, 0x14, 0xfe, 0x04, 0xf4, - 0x6c, 0xfe, 0x43, 0xf4, 0xb1, 0xfe, 0xf3, 0x10, 0xb7, 0x01, 0xfe, 0x8e, 0x13, 0x1a, 0x59, 0xaf, - 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x74, 0x99, 0xfe, 0xf8, 0x14, 0xa8, 0x74, 0xfe, 0x14, 0x10, - 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0xf1, 0x99, 0xfe, 0xf8, 0x14, 0xa8, 0xf1, 0xa4, 0x51, 0x9e, - 0x08, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x03, 0x51, 0x08, 0x0b, 0x03, 0x14, 0x06, 0x01, - 0x0c, 0x25, 0xec, 0x14, 0x0b, 0x01, 0x0c, 0x25, 0xec, 0x14, 0x18, 0x01, 0x0c, 0x25, 0xec, 0x78, - 0xfe, 0x89, 0x49, 0x01, 0x0c, 0x03, 0x14, 0x06, 0x01, 0x0c, 0x25, 0xbc, 0x14, 0x18, 0x01, 0x0c, - 0x25, 0xbc, 0x14, 0x06, 0x01, 0x0c, 0x25, 0xbc, 0xfe, 0x89, 0x49, 0x01, 0x0c, 0x25, 0xbc, 0x78, - 0xfe, 0x89, 0x4a, 0x01, 0x0c, 0x03, 0x51, 0x03, 0x29, 0xe8, 0x05, 0x06, 0x3b, 0xb6, 0x16, 0xe8, - 0xfe, 0x49, 0xf4, 0x00, 0x4f, 0x78, 0xce, 0x63, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf9, 0x01, - 0x0c, 0x40, 0x05, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0xb6, 0x15, 0x2b, 0x16, 0xfc, - 0x01, 0x55, 0x29, 0xfc, 0x05, 0x06, 0x50, 0x0a, 0x41, 0x06, 0x39, 0x03, 0x0d, 0x5d, 0x12, 0x91, - 0xfe, 0x43, 0x58, 0x01, 0x15, 0x05, 0x10, 0xfe, 0x1e, 0x12, 0x4a, 0xf3, 0x96, 0x01, 0x49, 0xfe, - 0x90, 0x4d, 0xe6, 0x10, 0xfe, 0xc5, 0x59, 0x01, 0x49, 0xfe, 0x8d, 0x56, 0xbf, 0x4a, 0x03, 0x4a, - 0x21, 0x91, 0x01, 0x15, 0x4a, 0x96, 0x01, 0x49, 0xeb, 0x10, 0xe6, 0x10, 0x21, 0x5d, 0x62, 0x1e, - 0x89, 0x0f, 0x5f, 0x01, 0xaa, 0x03, 0x0d, 0x5d, 0x12, 0x91, 0xfe, 0xc3, 0x58, 0x01, 0x15, 0x05, - 0x10, 0xfe, 0x1a, 0x12, 0x4a, 0xf3, 0x96, 0x01, 0x49, 0xeb, 0x10, 0xfe, 0x80, 0x4d, 0xfe, 0xc5, - 0x59, 0x01, 0x49, 0x4a, 0x03, 0x4a, 0x21, 0x5d, 0x01, 0x15, 0x4a, 0x96, 0x01, 0x49, 0xeb, 0x10, - 0xe6, 0x10, 0x21, 0x5d, 0x62, 0x1e, 0x89, 0x0f, 0x5f, 0x01, 0xaa, 0x03, 0x0d, 0x5d, 0x12, 0x91, - 0xfe, 0x43, 0x58, 0x01, 0x15, 0xfe, 0x42, 0x48, 0x96, 0x01, 0x49, 0xfe, 0xc0, 0x5a, 0xb7, 0xfe, - 0x00, 0xcd, 0xfe, 0x01, 0xcc, 0xfe, 0x4a, 0x46, 0xe4, 0x9c, 0x80, 0x05, 0x10, 0xfe, 0x2e, 0x13, - 0x5a, 0x5d, 0xfe, 0x4d, 0xf4, 0x1e, 0xfe, 0x1c, 0x13, 0x0f, 0x5f, 0x01, 0x8e, 0xb0, 0xfe, 0x40, - 0x4c, 0xfe, 0xc5, 0x58, 0x01, 0x49, 0xfe, 0x00, 0x07, 0x80, 0x05, 0x10, 0x89, 0x5a, 0x91, 0xfe, - 0x05, 0x57, 0xfe, 0x08, 0x10, 0xfe, 0x45, 0x58, 0x01, 0x49, 0xfe, 0x8d, 0x56, 0xbf, 0xfe, 0x80, - 0x4c, 0xfe, 0x05, 0x17, 0x03, 0x09, 0x10, 0x77, 0x6f, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, - 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xe3, 0x38, 0x9d, 0xfe, 0xfa, 0x16, 0x01, 0xfe, 0x08, 0x18, 0xd9, - 0x8d, 0x38, 0x6f, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xc0, 0x28, 0xfe, 0xea, 0x16, 0xfe, - 0xe2, 0x10, 0x09, 0x10, 0x77, 0x04, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x22, 0xfe, 0x18, 0x58, - 0x04, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x8d, 0x22, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, - 0xfe, 0x3c, 0x50, 0x6f, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x22, 0x9d, 0xfe, - 0x44, 0x17, 0xfe, 0xbe, 0x14, 0x35, 0x03, 0xc0, 0x28, 0xfe, 0x1c, 0x17, 0xfe, 0xa4, 0x10, 0x09, - 0x10, 0x77, 0xbf, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xdf, 0xe3, 0x30, 0x9d, 0xfe, 0x66, 0x17, 0xfe, - 0x9c, 0x14, 0xfe, 0x18, 0x13, 0x8d, 0x30, 0x6f, 0x1d, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, - 0xa7, 0x07, 0xfe, 0x7f, 0x00, 0xfe, 0x05, 0x40, 0x03, 0xc0, 0x28, 0xfe, 0x5a, 0x17, 0xfe, 0x6c, - 0x10, 0x09, 0x10, 0x77, 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x8d, 0xe1, 0x6f, 0x1d, 0xfe, 0x0f, - 0x79, 0xfe, 0x1c, 0xf7, 0xe1, 0x9d, 0xfe, 0xa6, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x03, 0xc0, 0x28, - 0xfe, 0x92, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x10, 0x77, 0xfe, 0x18, 0xfe, 0x66, 0xfe, - 0x19, 0xfe, 0x67, 0xd0, 0xe3, 0x46, 0x9d, 0xfe, 0xcc, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, - 0x8d, 0x46, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, - 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x6d, 0x31, 0x03, 0x6d, 0x31, 0xfe, 0x12, 0x45, 0x28, 0xfe, 0xbc, - 0x17, 0x17, 0x06, 0x4c, 0xfe, 0x9b, 0x00, 0xe5, 0x02, 0x27, 0xfe, 0x39, 0xf0, 0xfe, 0x10, 0x18, - 0x2b, 0x03, 0xfe, 0x7e, 0x18, 0x1a, 0x18, 0x87, 0x08, 0x0e, 0x03, 0x77, 0x04, 0xe7, 0x1a, 0x06, - 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x1c, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0x50, 0x4d, 0xfe, - 0x78, 0x14, 0xfe, 0x34, 0x12, 0x59, 0x8c, 0x37, 0x38, 0xc7, 0xfe, 0xe9, 0x13, 0x1c, 0x0f, 0x3f, - 0x01, 0x15, 0x05, 0x10, 0x50, 0x4d, 0xfe, 0x56, 0x14, 0xe9, 0x59, 0x8c, 0x37, 0x38, 0xc7, 0xfe, - 0xe9, 0x13, 0x09, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x13, 0xfe, 0x15, 0x00, 0x7a, 0xa5, 0x31, - 0x01, 0xea, 0x09, 0x06, 0x03, 0x0a, 0x41, 0x38, 0x39, 0x08, 0x3f, 0x09, 0xa2, 0x01, 0x45, 0x11, - 0x48, 0x08, 0x1e, 0x09, 0x52, 0x01, 0x7e, 0x09, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, - 0x36, 0xfe, 0xa8, 0x00, 0x21, 0x7b, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x03, 0x29, 0xc6, - 0x5b, 0x16, 0xc6, 0x03, 0x0f, 0xc8, 0x01, 0x15, 0xf2, 0x0f, 0x7d, 0x01, 0x15, 0xfe, 0x49, 0x44, - 0x28, 0xfe, 0x06, 0x19, 0x0f, 0x1e, 0x01, 0x15, 0x05, 0x10, 0x50, 0x0f, 0x5f, 0x01, 0xaa, 0x0f, - 0x7d, 0x01, 0x15, 0x5b, 0x80, 0x03, 0xfe, 0x40, 0x5e, 0xfe, 0xe2, 0x08, 0xfe, 0xc0, 0x4c, 0x29, - 0x3e, 0x05, 0x10, 0xfe, 0x52, 0x12, 0x4d, 0x05, 0x00, 0xfe, 0x18, 0x12, 0xfe, 0xe1, 0x18, 0xfe, - 0x19, 0xf4, 0xfe, 0x7f, 0x00, 0xaf, 0xfe, 0xe2, 0x08, 0x5b, 0x4d, 0x40, 0x05, 0x7b, 0xab, 0xfe, - 0x82, 0x48, 0xfe, 0x01, 0x80, 0xfe, 0xd7, 0x10, 0xfe, 0xc4, 0x48, 0x08, 0x2d, 0x09, 0x3e, 0xfe, - 0x40, 0x5f, 0x1c, 0x01, 0x45, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x14, 0x46, 0x08, 0x2d, 0x09, 0x3e, - 0x01, 0x45, 0x11, 0xfe, 0xdd, 0x00, 0xfe, 0x40, 0x4a, 0x72, 0xfe, 0x06, 0x17, 0xfe, 0x01, 0x07, - 0xfe, 0x82, 0x48, 0xfe, 0x04, 0x17, 0x03, 0xf5, 0x18, 0x79, 0xfe, 0x8e, 0x19, 0x04, 0xfe, 0x90, - 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xf5, 0xd4, 0x79, 0xfe, 0xa0, 0x19, 0x04, 0xfe, 0x92, - 0x00, 0xcf, 0x1d, 0xe0, 0xf5, 0xfe, 0x0b, 0x00, 0x79, 0xfe, 0xb2, 0x19, 0x04, 0xfe, 0x94, 0x00, - 0xcf, 0x22, 0xfe, 0x08, 0x10, 0x04, 0xfe, 0x96, 0x00, 0xcf, 0x8b, 0xfe, 0x4e, 0x45, 0xd8, 0xfe, - 0x0a, 0x45, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, 0x10, 0x1a, 0x74, 0xfe, 0x08, 0x1c, 0xfe, 0x67, - 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0xd8, 0xfe, 0x48, 0xf4, 0x18, 0x99, - 0xfe, 0xe6, 0x19, 0x08, 0x18, 0x03, 0x05, 0x84, 0xfe, 0x5a, 0xf0, 0xfe, 0xf6, 0x19, 0x20, 0xfe, - 0x09, 0x00, 0xfe, 0x34, 0x10, 0x05, 0x1d, 0xfe, 0x5a, 0xf0, 0xfe, 0x04, 0x1a, 0x20, 0xd5, 0xfe, - 0x26, 0x10, 0x05, 0x18, 0x87, 0x20, 0x8b, 0xe0, 0x05, 0x0b, 0x87, 0x20, 0xb1, 0xfe, 0x0e, 0x10, - 0x05, 0x06, 0x87, 0x20, 0x5e, 0xce, 0xb6, 0x03, 0x17, 0xfe, 0x09, 0x00, 0x01, 0x3b, 0x2f, 0xfe, - 0x34, 0x1a, 0x04, 0x76, 0xb7, 0x03, 0x1b, 0xfe, 0x54, 0x1a, 0xfe, 0x14, 0xf0, 0x0c, 0x2f, 0xfe, - 0x48, 0x1a, 0x1b, 0xfe, 0x54, 0x1a, 0xfe, 0x82, 0xf0, 0xfe, 0x4c, 0x1a, 0x03, 0xff, 0x15, 0x00, - 0x00, + 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4, 0x01, 0x00, 0x48, 0xe4, + 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, + 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, + 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0, 0x18, 0xf4, 0x08, 0x00, + 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, + 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00, + 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13, 0xba, 0x13, 0x18, 0x40, + 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, + 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01, + 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12, 0x08, 0x12, 0x02, 0x4a, + 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, + 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, + 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d, 0x06, 0x13, 0x4c, 0x1c, + 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, + 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, + 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa, 0x05, 0x00, 0x34, 0x00, + 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, + 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54, + 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, + 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, + 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03, + 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13, 0x12, 0x13, 0x24, 0x14, + 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, + 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55, + 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0, 0x04, 0xf8, + 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, + 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01, + 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08, 0x68, 0x08, 0x69, 0x08, + 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, + 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14, + 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18, 0xca, 0x18, 0xe6, 0x19, + 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, + 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24, + 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, + 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xd6, + 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, + 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d, 0x02, 0xfe, 0xc8, 0x0d, + 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, + 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02, + 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02, 0xfe, 0x46, 0xf0, 0xfe, + 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, + 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14, + 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, + 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, + 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd, + 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x18, 0x06, + 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, + 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, + 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe, 0x69, 0x10, 0x18, 0x06, + 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, + 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, + 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x09, + 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, + 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, + 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x40, 0x1c, 0x1c, + 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, + 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02, + 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13, 0x21, 0x22, 0xa3, 0xb7, + 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, + 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27, + 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe, 0x06, 0xf0, 0xfe, 0xc8, + 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, + 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19, + 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x74, 0x01, 0xaf, 0x8c, + 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, + 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, + 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d, 0xfe, 0x3c, 0x04, 0x3b, + 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, + 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe, + 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0x4f, 0x79, 0x2a, + 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, + 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe, + 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x08, 0x13, 0x32, 0x07, + 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, + 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6, + 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36, 0x02, 0x2b, 0xfe, 0x42, + 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, + 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c, + 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28, 0x17, 0xfe, 0x90, 0x05, + 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, + 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48, + 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0x12, 0xfe, 0xe3, 0x00, + 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, + 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02, + 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2, 0x08, 0x53, 0x05, 0xcb, + 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, + 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, + 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb, 0x03, 0x5c, 0x28, 0xfe, + 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, + 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, + 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62, 0x12, 0x03, 0x45, 0x28, + 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, + 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2, + 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01, 0xfe, 0xcc, 0x15, 0x1d, + 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, + 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb, + 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, + 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, + 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01, + 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38, 0x12, 0x08, 0x05, 0x1a, + 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, + 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe, + 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b, 0xfe, 0x09, 0x6f, 0xba, + 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, + 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01, + 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe, 0x2c, 0x90, 0xfe, 0xae, + 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, + 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe, + 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b, 0x37, 0x01, 0xb3, 0xb8, + 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, + 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c, + 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d, 0x14, 0x3e, 0xfe, 0x4a, + 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, + 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe, + 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, + 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, + 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e, + 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe, 0x9a, 0x08, 0xc6, 0xfe, + 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, + 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12, + 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e, 0x1c, 0x02, 0xfe, 0x18, + 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, + 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7, + 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18, 0xfe, 0xf1, 0x18, 0xfe, + 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, + 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5, + 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18, 0x0b, 0xb6, 0xfe, 0xbf, + 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, + 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5, + 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15, 0x9d, 0x01, 0x36, 0x10, + 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, + 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe, + 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0x08, 0x05, + 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, + 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49, + 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x8f, 0xfe, 0xe3, 0x54, + 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, + 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b, + 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00, 0xad, 0xfe, 0x01, 0x59, + 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, + 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b, + 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63, 0x02, 0x4a, 0x08, 0x05, + 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, + 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a, + 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29, 0x61, 0x0c, 0x7f, 0x14, + 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, + 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef, + 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40, 0xe4, 0x08, 0x05, 0x1f, + 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, + 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05, + 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19, 0x81, 0x50, 0xfe, 0x10, + 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, + 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c, + 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7, 0x08, 0x05, 0x0a, 0xfe, + 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, + 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed, + 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe, 0x00, 0xff, 0x35, 0xfe, + 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, + 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe, + 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, + 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, + 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0, + 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea, 0x0b, 0x10, 0x58, 0xfe, + 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, + 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34, + 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20, 0x0c, 0x1c, 0x34, 0x94, + 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, + 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33, + 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24, 0x33, 0x31, 0xdf, 0xbc, + 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, + 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28, + 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x44, 0xfe, 0x28, 0x00, + 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, + 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10, + 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xac, + 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, + 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08, + 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05, 0x1a, 0xfe, 0x58, 0x12, + 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, + 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10, + 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10, 0xfe, 0x13, 0x00, 0xfe, + 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, + 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe, + 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0, 0xb4, 0x15, 0xfe, 0x31, + 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, + 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75, + 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x44, 0x48, + 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, + 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d, + 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0xce, 0x47, 0xfe, 0xad, + 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, + 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06, + 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe, 0x3a, 0x01, 0x56, 0xfe, + 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, + 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, + 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13, 0x15, 0x1a, 0x39, 0xa0, + 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, + 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12, + 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12, 0x22, 0x9f, 0xb7, 0x13, + 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, + 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc, + 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21, 0xfe, 0x00, 0xcc, 0x04, + 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, + 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe, + 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x0a, 0xfe, 0x3c, 0x50, + 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, + 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01, + 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, + 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, + 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79, + 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, + + 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, + 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52, + 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc, 0x0f, 0x44, 0x11, 0x0f, + 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, + 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, + 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x04, 0x42, + 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, + 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f, + 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, + 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, + 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d, 0xfe, 0x01, 0xec, 0xa2, + 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, + 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07, + 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17, 0xfe, 0x32, 0x12, 0x07, + 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, + 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d, + 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d, 0x32, 0x07, 0xa6, 0xfe, + 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, + 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03, + 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21, 0x0c, 0x7f, 0x0c, 0x80, + 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, + 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f, + 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40, 0x88, 0x9b, 0x2e, 0x9c, + 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, + 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61, + 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, + 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, + 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d, + 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23, 0x72, 0x01, 0xaf, 0x1e, + 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, + 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19, + 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, + 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, + 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8, + 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53, 0x05, 0x1f, 0x35, 0xa9, + 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, + 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35, + 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x03, 0x5c, 0xc1, 0x0c, + 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, + 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1, + 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a, 0xf4, 0x06, 0xea, 0x32, + 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, + 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13, + 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0, 0x13, 0x1c, 0xfe, 0xd0, + 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, + 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f, + 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, + 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, + 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03, + 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52, 0xfe, 0x00, 0x7d, 0xfe, + 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, + 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01, + 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, + 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, + 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee, + 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c, 0x30, 0xfe, 0x78, 0x10, + 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, + 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00, + 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28, 0x10, 0x69, 0x06, 0xfe, + 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, + 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe, + 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4, 0x9e, 0xfe, 0xf3, 0x10, + 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, + 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, + 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d, 0xf4, 0x00, 0xe9, 0x91, + 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, + 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76, + 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x19, 0x01, 0x0b, + 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, + 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8, + 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, + 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, + 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06, + 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e, 0x07, 0x11, 0xae, 0x09, + 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, + 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e, + 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x4c, + 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, + 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, + 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4, 0x17, 0xad, 0x9a, 0x1b, + 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, + 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe, + 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, + 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, + 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75, + 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x2e, 0x97, 0xfe, 0x5a, + 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, + 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe, + 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xcb, 0x97, 0xfe, 0x92, + 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, + 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d, + 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x9a, 0x5b, 0x41, 0xfe, + 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, + 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39, + 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04, 0xfe, 0x7e, 0x18, 0x1e, + 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, + 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09, + 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, + 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, + 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, + 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c, 0xe7, 0x0a, 0x10, 0xfe, + 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, + 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b, + 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77, 0x13, 0xa3, 0x04, 0x09, + 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, + 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09, + 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe, 0x1c, 0x19, 0x03, 0xfe, + 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, + 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b, + 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe, 0x08, 0x10, 0x03, 0xfe, + 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, + 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00, + 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19, 0x04, 0x07, 0x7e, 0xfe, + 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, + 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07, + 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59, 0xa9, 0xb8, 0x04, 0x15, + 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, + 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0, + 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00, }; STATIC unsigned short _adv_asc38C0800_size = - sizeof(_adv_asc38C0800_buf); /* 0x14F1 */ + sizeof(_adv_asc38C0800_buf); /* 0x14E1 */ STATIC ADV_DCNT _adv_asc38C0800_chksum = - 0x053503A5; /* Expanded checksum. */ + 0x050D3FD8UL; /* Expanded little-endian checksum. */ + +/* Microcode buffer is kept after initialization for error recovery. */ +STATIC unsigned char _adv_asc38C1600_buf[] = { + 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0, 0x18, 0xe4, 0x01, 0x00, + 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, + 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0, + 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00, 0x98, 0x57, 0x01, 0xe6, + 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, + 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0, + 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01, 0x06, 0x13, 0x0c, 0x1c, + 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, + 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea, + 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x04, 0x13, 0xbb, 0x55, + 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c, + 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, + 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, + 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48, + 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x06, 0x00, + 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, + 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0, + 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, + 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, + 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16, + 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, + 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, + 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c, + 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x42, 0x1d, 0x08, 0x44, + 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, + 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, + 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0xa8, 0x00, 0xaa, 0x00, + 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, + 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d, + 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10, 0xf3, 0x10, 0x06, 0x12, + 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, + 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff, + 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24, + 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, + 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13, + 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xe8, + 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, + 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, + 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d, 0x05, 0xfe, 0x08, 0x0f, + 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, + 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90, + 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8, 0x02, 0xfe, 0x46, 0xf0, + 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, + 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07, + 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xf5, 0xfe, 0x1e, + 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, + 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe, + 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x1c, + 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, + 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01, + 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09, 0x1a, 0x31, 0xfe, 0x69, + 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, + 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51, + 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, + 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, + 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30, + 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0, 0xfe, 0xe4, 0x01, 0xfe, + 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, + 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f, + 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05, 0x70, 0x37, 0xfe, 0x48, + 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, + 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe, + 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32, 0x15, 0xfe, 0xe4, 0x00, + 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, + 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b, + 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xfe, 0x46, 0x1c, + 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, + 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77, + 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, + 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, + 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01, + 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25, 0xee, 0xfe, 0x4c, 0x44, + 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, + 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe, + 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10, 0x13, 0x34, 0xfe, 0x4c, + 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, + 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f, + 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f, 0xfe, 0xa4, 0x0e, 0x05, + 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, + 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46, + 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04, 0xfe, 0x87, 0x83, 0xfe, + 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, + 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06, + 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda, 0x05, 0xd0, 0x54, 0x01, + 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, + 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, + 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01, 0x38, 0xfe, 0x4a, 0xf0, + 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, + 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0, + 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe, 0x1c, 0x00, 0x4d, 0x01, + 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, + 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, + 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13, 0x03, 0xb6, 0x1e, 0xfe, + 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, + 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68, + 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x03, 0x9a, 0x1e, 0xfe, + 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, + 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00, + 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17, 0xfe, 0xea, 0x06, 0x01, + 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, + 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae, + 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a, 0x1e, 0xfe, 0x1a, 0x12, + 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, + 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6, + 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x17, 0xfe, + 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, + 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05, + 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0x9c, 0x32, 0x5f, + 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, + 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29, + 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, + 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, + 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13, + 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, + 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, + 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c, + 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x53, 0x63, 0x4e, + 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, + 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c, + 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe, 0x1e, 0xfe, 0x99, 0x58, + 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, + 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a, + 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40, 0x01, 0x0c, 0x61, 0x65, + 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, + 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e, + 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e, 0x01, 0xfe, 0xfe, 0x1e, + 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, + 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b, + 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04, 0xfe, 0x9f, 0x83, 0x33, + 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, + 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e, + 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90, 0x04, 0xfe, 0xc0, 0x93, + 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, + 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, + 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5, + 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, + 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41, + 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07, 0xfe, 0x14, 0x12, 0x01, + 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, + 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe, + 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe, 0x92, 0x10, 0xc4, 0xf6, + 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, + 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0, + 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07, 0x1b, 0xbf, 0xd4, 0x5b, + 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, + 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74, + 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78, 0x0f, 0x4d, 0x01, 0xfe, + 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, + 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21, + 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe, 0x83, 0x83, 0xfe, 0xc9, + 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, + 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b, + 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0x10, + 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, + 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64, + 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97, 0x10, 0x98, 0x91, 0x6c, + 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, + 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, + 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x01, 0x0c, + 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, + 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe, + 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb, 0x01, 0x0c, 0x06, 0x0d, + 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, + 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e, + 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, + 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, + 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51, + 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe, 0x76, 0x10, 0xac, 0xfe, + 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, + 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92, + 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2, 0x0c, 0xfe, 0x3e, 0x10, + 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, + 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94, + 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3, 0xfe, 0xcc, 0xf0, 0xef, + 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, + 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5, + 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32, 0x2f, 0xfe, 0x3e, 0x0d, + 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, + 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99, + 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8, 0x9c, 0x2f, 0xfe, 0x8c, + 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, + 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13, + 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b, 0xfe, 0xda, 0x0e, 0x0a, + 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, + 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85, + 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe, 0xcc, 0x10, 0x01, 0xa7, + 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, + 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2, + 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x40, 0x15, + 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, + 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe, + 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, + 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, + 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19, + 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19, 0xfe, 0x41, 0x00, 0xa2, + 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, + 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c, + 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01, 0xfe, 0xd4, 0x11, 0x05, + 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, + 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56, + 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01, 0x0c, 0x06, 0x28, 0xfe, + 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, + 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe, + 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x05, + 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, + 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b, + 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe, 0xf0, 0x1a, 0x03, 0xfe, + 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, + 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b, + 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02, 0xea, 0xe7, 0x53, 0x92, + 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, + 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e, + 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02, 0x26, 0x02, 0x21, 0x96, + 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, + 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe, + 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe, 0x00, 0xcc, 0x02, 0xfe, + 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, + 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80, + 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe, 0x1d, 0x80, 0x04, 0xfe, + 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, + 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, + 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09, 0x56, 0xfb, 0x01, 0xfe, + 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, + 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e, + 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe, 0x96, 0x90, 0x04, 0xfe, + 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, + 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01, + 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40, 0x21, 0x2c, 0xfe, 0x00, + 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, + 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, + 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10, 0x66, 0x10, 0x55, 0x10, + 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, + 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, + 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, + 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, + 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47, + 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01, 0xa7, 0x90, 0x34, 0x60, + 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, + 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, + 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, + 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, + 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e, + 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01, 0xf4, 0xfe, 0xdd, 0x10, + 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, + 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23, + 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09, 0x24, 0xfe, 0x12, 0x12, + 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, + 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43, + 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80, 0x13, 0x01, 0x0c, 0x06, + 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, + 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10, + 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49, 0x88, 0x20, 0x6e, 0x01, + 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, + 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe, + 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, 0xe5, + 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, + 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50, + 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x68, 0x3b, + 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, + 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25, + 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01, 0xa6, 0x23, 0x3f, 0x1b, + 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, + 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01, + 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, + 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, + 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08, + 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03, 0xb6, 0x1e, 0x83, 0x01, + 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, + 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82, + 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e, 0x05, 0x72, 0xfe, 0xc0, + 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, + 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, + 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe, 0xe8, 0x14, 0x01, 0xa6, + 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, + 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, + 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, 0x09, + 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, + 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72, + 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0xc0, 0x19, 0x05, + 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, + 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32, + 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0xfe, 0xff, + 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, + 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, + 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e, 0x02, 0x13, 0x58, 0xff, + 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, + 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54, + 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07, 0x7c, 0x3a, 0x0b, 0x0e, + 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, + 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe, + 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77, 0x02, 0x01, 0xc6, 0xfe, + 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, + 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe, + 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12, 0x48, 0xfe, 0x08, 0x17, + 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, + 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55, + 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x1c, 0x63, 0x13, + 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, + 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60, + 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8, 0x00, 0x1c, 0x95, 0x13, + 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, + 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b, + 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x49, + 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, + 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13, + 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xbe, 0xfe, 0x03, + 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, + 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9, + 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, + 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, + 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e, + 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10, 0xfe, 0x40, 0x5a, 0x23, + 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, + 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, + 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe, 0x43, 0x48, 0x2d, 0x93, + 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, + 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0, + 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa, 0x18, 0x45, 0xfe, 0x1c, + 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, + 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01, + 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe, 0x7e, 0x01, 0xfe, 0xc8, + 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, + 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14, + 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, + 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, + 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1, + 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01, 0x08, 0x02, 0x50, 0x02, + 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, + 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe, + 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17, 0x74, 0x5f, 0xcc, 0x01, + 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, + 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, + 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13, 0x16, 0xfe, 0x64, 0x1a, + 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, + 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, + 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa, 0xfe, 0x80, 0xe7, 0x1a, + 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, + 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80, + 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x0a, + 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, + 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3, + 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe, 0xf4, 0x1a, 0xfe, 0xfa, + 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, + 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07, + 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x24, 0xb1, 0xfe, + 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, + 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1, + 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe, 0xaf, 0x19, 0xfe, 0x98, + 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, + 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04, + 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a, 0x7c, 0x12, 0xfe, 0x0f, + 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, + 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe, + 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee, 0x1b, 0xfe, 0x36, 0x14, + 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, + 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45, + 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe, 0x39, 0xf0, 0x75, 0x26, + 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, + 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13, + 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, + 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, + 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01, + 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, 0x56, + 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, + 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80, + 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, + 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, + 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44, + 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09, 0x1a, 0xa4, 0x0a, 0x67, + 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, + 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b, + 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10, 0xfe, 0x4e, 0xe4, 0xfe, + 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, + 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1, + 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, + 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, + 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8, + 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe, 0x1a, 0x10, 0x09, 0x0d, + 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, + 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08, + 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e, 0xfe, 0x82, 0xf0, 0xfe, + 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, + 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82, + 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86, 0x83, 0x33, 0x0b, 0x0e, + 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, + 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80, + 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04, 0xfe, 0x99, 0x83, 0xfe, + 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, + 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x08, 0x90, 0x04, + 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, + 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, + 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x3c, 0x90, 0x04, + 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, + 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00, +}; + +STATIC unsigned short _adv_asc38C1600_size = + sizeof(_adv_asc38C1600_buf); /* 0x1673 */ +STATIC ADV_DCNT _adv_asc38C1600_chksum = + 0x0604EF77UL; /* Expanded little-endian checksum. */ /* a_init.c */ /* @@ -15455,6 +14570,14 @@ * configuration. The BIOS now uses this structure when it is built. * Additional structure information can be found in a_condor.h where * the structure is defined. + * + * The *_Field_IsChar structs are needed to correct for endianness. + * These values are read from the board 16 bits at a time directly + * into the structs. Because some fields are char, the values will be + * in the wrong order. The *_Field_IsChar tells when to flip the + * bytes. Data read and written to PCI memory is automatically swapped + * on big-endian platforms so char fields read as words are actually being + * unswapped on big-endian platforms. */ STATIC ADVEEP_3550_CONFIG Default_3550_EEPROM_Config ASC_INITDATA = { @@ -15494,6 +14617,44 @@ 0 /* num_of_err */ }; +STATIC ADVEEP_3550_CONFIG +ADVEEP_3550_Config_Field_IsChar ASC_INITDATA = { + 0, /* cfg_lsw */ + 0, /* cfg_msw */ + 0, /* -disc_enable */ + 0, /* wdtr_able */ + 0, /* sdtr_able */ + 0, /* start_motor */ + 0, /* tagqng_able */ + 0, /* bios_scan */ + 0, /* scam_tolerant */ + 1, /* adapter_scsi_id */ + 1, /* bios_boot_delay */ + 1, /* scsi_reset_delay */ + 1, /* bios_id_lun */ + 1, /* termination */ + 1, /* reserved1 */ + 0, /* bios_ctrl */ + 0, /* ultra_able */ + 0, /* reserved2 */ + 1, /* max_host_qng */ + 1, /* max_dvc_qng */ + 0, /* dvc_cntl */ + 0, /* bug_fix */ + 0, /* serial_number_word1 */ + 0, /* serial_number_word2 */ + 0, /* serial_number_word3 */ + 0, /* check_sum */ + { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* oem_name[16] */ + 0, /* dvc_err_code */ + 0, /* adv_err_code */ + 0, /* adv_err_addr */ + 0, /* saved_dvc_err_code */ + 0, /* saved_adv_err_code */ + 0, /* saved_adv_err_addr */ + 0 /* num_of_err */ +}; + STATIC ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config ASC_INITDATA = { ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ @@ -15559,6 +14720,201 @@ 0 /* 63 reserved */ }; +STATIC ADVEEP_38C0800_CONFIG +ADVEEP_38C0800_Config_Field_IsChar ASC_INITDATA = { + 0, /* 00 cfg_lsw */ + 0, /* 01 cfg_msw */ + 0, /* 02 disc_enable */ + 0, /* 03 wdtr_able */ + 0, /* 04 sdtr_speed1 */ + 0, /* 05 start_motor */ + 0, /* 06 tagqng_able */ + 0, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 1, /* 09 adapter_scsi_id */ + 1, /* bios_boot_delay */ + 1, /* 10 scsi_reset_delay */ + 1, /* bios_id_lun */ + 1, /* 11 termination_se */ + 1, /* termination_lvd */ + 0, /* 12 bios_ctrl */ + 0, /* 13 sdtr_speed2 */ + 0, /* 14 sdtr_speed3 */ + 1, /* 15 max_host_qng */ + 1, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + 0, /* 58 subsysvid */ + 0, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + +STATIC ADVEEP_38C1600_CONFIG +Default_38C1600_EEPROM_Config ASC_INITDATA = { + ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ + 0x0000, /* 01 cfg_msw */ + 0xFFFF, /* 02 disc_enable */ + 0xFFFF, /* 03 wdtr_able */ + 0x5555, /* 04 sdtr_speed1 */ + 0xFFFF, /* 05 start_motor */ + 0xFFFF, /* 06 tagqng_able */ + 0xFFFF, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 7, /* 09 adapter_scsi_id */ + 0, /* bios_boot_delay */ + 3, /* 10 scsi_reset_delay */ + 0, /* bios_id_lun */ + 0, /* 11 termination_se */ + 0, /* termination_lvd */ + 0xFFE7, /* 12 bios_ctrl */ + 0x5555, /* 13 sdtr_speed2 */ + 0x5555, /* 14 sdtr_speed3 */ + ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ + ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0x5555, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + ADV_PCI_VENDOR_ID, /* 58 subsysvid */ + ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + +STATIC ADVEEP_38C1600_CONFIG +ADVEEP_38C1600_Config_Field_IsChar ASC_INITDATA = { + 0, /* 00 cfg_lsw */ + 0, /* 01 cfg_msw */ + 0, /* 02 disc_enable */ + 0, /* 03 wdtr_able */ + 0, /* 04 sdtr_speed1 */ + 0, /* 05 start_motor */ + 0, /* 06 tagqng_able */ + 0, /* 07 bios_scan */ + 0, /* 08 scam_tolerant */ + 1, /* 09 adapter_scsi_id */ + 1, /* bios_boot_delay */ + 1, /* 10 scsi_reset_delay */ + 1, /* bios_id_lun */ + 1, /* 11 termination_se */ + 1, /* termination_lvd */ + 0, /* 12 bios_ctrl */ + 0, /* 13 sdtr_speed2 */ + 0, /* 14 sdtr_speed3 */ + 1, /* 15 max_host_qng */ + 1, /* max_dvc_qng */ + 0, /* 16 dvc_cntl */ + 0, /* 17 sdtr_speed4 */ + 0, /* 18 serial_number_word1 */ + 0, /* 19 serial_number_word2 */ + 0, /* 20 serial_number_word3 */ + 0, /* 21 check_sum */ + { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */ + 0, /* 30 dvc_err_code */ + 0, /* 31 adv_err_code */ + 0, /* 32 adv_err_addr */ + 0, /* 33 saved_dvc_err_code */ + 0, /* 34 saved_adv_err_code */ + 0, /* 35 saved_adv_err_addr */ + 0, /* 36 reserved */ + 0, /* 37 reserved */ + 0, /* 38 reserved */ + 0, /* 39 reserved */ + 0, /* 40 reserved */ + 0, /* 41 reserved */ + 0, /* 42 reserved */ + 0, /* 43 reserved */ + 0, /* 44 reserved */ + 0, /* 45 reserved */ + 0, /* 46 reserved */ + 0, /* 47 reserved */ + 0, /* 48 reserved */ + 0, /* 49 reserved */ + 0, /* 50 reserved */ + 0, /* 51 reserved */ + 0, /* 52 reserved */ + 0, /* 53 reserved */ + 0, /* 54 reserved */ + 0, /* 55 reserved */ + 0, /* 56 cisptr_lsw */ + 0, /* 57 cisprt_msw */ + 0, /* 58 subsysvid */ + 0, /* 59 subsysid */ + 0, /* 60 reserved */ + 0, /* 61 reserved */ + 0, /* 62 reserved */ + 0 /* 63 reserved */ +}; + /* * Initialize the ADV_DVC_VAR structure. * @@ -15639,11 +14995,11 @@ asc_dvc->cfg->chip_version = AdvGetChipVersion(iop_base, asc_dvc->bus_type); - ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: %x %x\n", + ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n", (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1), (ushort) ADV_CHIP_ID_BYTE); - ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: %x %x\n", + ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n", (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0), (ushort) ADV_CHIP_ID_WORD); @@ -15676,7 +15032,13 @@ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG); - if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + if ((status = AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) + { + return ADV_ERROR; + } + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) { @@ -15702,6 +15064,8 @@ * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. + * + * Needed after initialization for error recovery. */ STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) @@ -15814,22 +15178,662 @@ { AdvWriteWordAutoIncLram(iop_base, (((ushort) _adv_asc3550_buf[i + 3] << 8) | - _adv_asc3550_buf[i + 2])); + _adv_asc3550_buf[i + 2])); word++; } i += 3; } else if (_adv_asc3550_buf[i] == 0xfe) { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf[i + 2] << 8) | - _adv_asc3550_buf[i + 1])); + _adv_asc3550_buf[i + 2] << 8) | + _adv_asc3550_buf[i + 1])); + i += 2; + word++; + } else + { + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | + _adv_asc3550_buf[_adv_asc3550_buf[i] * 2])); + word++; + } + } + + /* + * Set 'word' for later use to clear the rest of memory and save + * the expanded mcode size. + */ + word *= 2; + adv_asc3550_expanded_size = word; + + /* + * Clear the rest of ASC-3550 Internal RAM (8KB). + */ + for (; word < ADV_3550_MEMSIZE; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, 0); + } + + /* + * Verify the microcode checksum. + */ + sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + for (word = 0; word < adv_asc3550_expanded_size; word += 2) + { + sum += AdvReadWordAutoIncLram(iop_base); + } + + if (sum != _adv_asc3550_chksum) + { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return ADV_ERROR; + } + + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); + for (word = begin_addr; word < end_addr; word += 2) + { + code_sum += AdvReadWordAutoIncLram(iop_base); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); + + /* + * Read and save microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); + + /* + * Set the chip type to indicate the ASC3550. + */ + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) + { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO + * threshold of 128 bytes. This register is only accessible to the host. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + START_CTL_EMFU | READ_CMD_MRM); + + /* + * Microcode operating variables for WDTR, SDTR, and command tag + * queuing will be set in AdvInquiryHandling() based on what a + * device reports it is capable of in Inquiry byte 7. + * + * If SCSI Bus Resets have been disabled, then directly set + * SDTR and WDTR from the EEPROM configuration. This will allow + * the BIOS and warm boot to work without a SCSI bus hang on + * the Inquiry caused by host and target mismatched DTR values. + * Without the SCSI Bus Reset, before an Inquiry a device can't + * be assumed to be in Asynchronous, Narrow mode. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) + { + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able); + } + + /* + * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID + * bitmask. These values determine the maximum SDTR speed negotiated + * with a device. + * + * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, + * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them + * without determining here whether the device supports SDTR. + * + * 4-bit speed SDTR speed name + * =========== =============== + * 0000b (0x0) SDTR disabled + * 0001b (0x1) 5 Mhz + * 0010b (0x2) 10 Mhz + * 0011b (0x3) 20 Mhz (Ultra) + * 0100b (0x4) 40 Mhz (LVD/Ultra2) + * 0101b (0x5) 80 Mhz (LVD2/Ultra3) + * 0110b (0x6) Undefined + * . + * 1111b (0xF) Undefined + */ + word = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) + { + /* Set Ultra speed for TID 'tid'. */ + word |= (0x3 << (4 * (tid % 4))); + } else + { + /* Set Fast speed for TID 'tid'. */ + word |= (0x2 << (4 * (tid % 4))); + } + if (tid == 3) /* Check if done with sdtr_speed1. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); + word = 0; + } else if (tid == 7) /* Check if done with sdtr_speed2. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); + word = 0; + } else if (tid == 11) /* Check if done with sdtr_speed3. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); + word = 0; + } else if (tid == 15) /* Check if done with sdtr_speed4. */ + { + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); + /* End of loop. */ + } + } + + /* + * Set microcode operating variable for the disconnect per TID bitmask. + */ + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); + + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); + + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + + /* + * If all three connectors are in use, return an error. + */ + if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || + (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) + { + asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; + return ADV_ERROR; + } + + /* + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) + { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } + + /* + * If this is a differential board and a single-ended device + * is attached to one of the connectors, return an error. + */ + if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) + { + asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + return ADV_ERROR; + } + + /* + * If automatic termination control is enabled, then set the + * termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting + * then 'termination' was set-up in AdvInitFrom3550EEPROM() and + * is ready to be 'ored' into SCSI_CFG1. + */ + if (asc_dvc->cfg->termination == 0) + { + /* + * The software always controls termination by setting TERM_CTL_SEL. + * If TERM_CTL_SEL were set to 0, the hardware would set termination. + */ + asc_dvc->cfg->termination |= TERM_CTL_SEL; + + switch(scsi_cfg1 & CABLE_DETECT) + { + /* TERM_CTL_H: on, TERM_CTL_L: on */ + case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF: + asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + break; + + /* TERM_CTL_H: on, TERM_CTL_L: off */ + case 0x1: case 0x5: case 0x9: case 0xA: case 0xC: + asc_dvc->cfg->termination |= TERM_CTL_H; + break; + + /* TERM_CTL_H: off, TERM_CTL_L: off */ + case 0x2: case 0x6: + break; + } + } + + /* + * Clear any set TERM_CTL_H and TERM_CTL_L bits. + */ + scsi_cfg1 &= ~TERM_CTL; + + /* + * Invert the TERM_CTL_H and TERM_CTL_L bits and then + * set 'scsi_cfg1'. The TERM_POL bit does not need to be + * referenced, because the hardware internally inverts + * the Termination High and Low bits if TERM_POL is set. + */ + scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set filter value and possibly modified termination control + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, + FLTR_DISABLE | scsi_cfg1); + + /* + * Set MEM_CFG Microcode Default Value + * + * The microcode will set the MEM_CFG register using this value + * after it is started below. + * + * MEM_CFG may be accessed as a word or byte, but only bits 0-7 + * are defined. + * + * ASC-3550 has 8KB internal memory. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + BIOS_EN | RAM_SZ_8KB); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + /* + * Build carrier freelist. + * + * Driver must have already allocated memory and set 'carrier_buf'. + */ + ASC_ASSERT(asc_dvc->carrier_buf != NULL); + + carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); + asc_dvc->carr_freelist = NULL; + if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) + { + buf_size = ADV_CARRIER_BUFSIZE; + } else + { + buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); + } + + do { + /* + * Get physical address of the carrier 'carrp'. + */ + contig_len = sizeof(ADV_CARR_T); + carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp, + (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG)); + + buf_size -= sizeof(ADV_CARR_T); + + /* + * If the current carrier is not physically contiguous, then + * maybe there was a page crossing. Try the next carrier aligned + * start address. + */ + if (contig_len < sizeof(ADV_CARR_T)) + { + carrp++; + continue; + } + + carrp->carr_pa = carr_paddr; + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); + + /* + * Insert the carrier at the beginning of the freelist. + */ + carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); + asc_dvc->carr_freelist = carrp; + + carrp++; + } + while (buf_size > 0); + + /* + * Set-up the Host->RISC Initiator Command Queue (ICQ). + */ + + if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); + + /* + * The first command issued will be placed in the stopper carrier. + */ + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC ICQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + + /* + * Set-up the RISC->Host Initiator Response Queue (IRQ). + */ + if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) + { + asc_dvc->err_code |= ASC_IERR_NO_CARRIER; + return ADV_ERROR; + } + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); + + /* + * The first command completed by the RISC will be placed in + * the stopper. + * + * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is + * completed the RISC will set the ASC_RQ_STOPPER bit. + */ + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); + + /* + * Set RISC IRQ physical address start value. + */ + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); + asc_dvc->carr_pending_cnt = 0; + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. The RISC has to be running + * to issue a SCSI Bus Reset. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + { + /* + * If the BIOS Signature is present in memory, restore the + * BIOS Handshake Configuration Table and do not perform + * a SCSI Bus Reset. + */ + if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) + { + /* + * Restore per TID negotiated values. + */ + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + } else + { + if (AdvResetSB(asc_dvc) != ADV_TRUE) + { + warn_code = ASC_WARN_BUSRESET_ERROR; + } + } + } + + return warn_code; +} + +/* + * Initialize the ASC-38C0800. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Needed after initialization for error recovery. + */ +STATIC int +AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADV_DCNT sum; + int begin_addr; + int end_addr; + ushort code_sum; + int word; + int j; + int adv_asc38C0800_expanded_size; + ADV_CARR_T *carrp; + ADV_DCNT contig_len; + ADV_SDCNT buf_size; + ADV_PADDR carr_paddr; + int i; + ushort scsi_cfg1; + uchar byte; + uchar tid; + ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */ + ushort wdtr_able, sdtr_able, tagqng_able; + uchar max_cmd[ADV_MAX_TID + 1]; + + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + { + return ADV_ERROR; + } + + /* + * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. + */ + if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) + { + asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; + return ADV_ERROR; + } + + warn_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN/2; i++) + { + AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + } + + /* + * Save current per TID negotiated values. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + max_cmd[tid]); + } + + /* + * RAM BIST (RAM Built-In Self Test) + * + * Address : I/O base + offset 0x38h register (byte). + * Function: Bit 7-6(RW) : RAM mode + * Normal Mode : 0x00 + * Pre-test Mode : 0x40 + * RAM Test Mode : 0x80 + * Bit 5 : unused + * Bit 4(RO) : Done bit + * Bit 3-0(RO) : Status + * Host Error : 0x08 + * Int_RAM Error : 0x04 + * RISC Error : 0x02 + * SCSI Error : 0x01 + * No Error : 0x00 + * + * Note: RAM BIST code should be put right here, before loading the + * microcode and after saving the RISC memory BIOS region. + */ + + /* + * LRAM Pre-test + * + * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. + * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return + * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset + * to NORMAL_MODE, return an error too. + */ + for (i = 0; i < 2; i++) + { + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE) + { + asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } + + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */ + if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) + != NORMAL_VALUE) + { + asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST; + return ADV_ERROR; + } + } + + /* + * LRAM Test - It takes about 1.5 ms to run through the test. + * + * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. + * If Done bit not set or Status not 0, save register byte, set the + * err_code, and return an error. + */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); + DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */ + + byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); + if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) + { + /* Get here if Done bit not set or Status not 0. */ + asc_dvc->bist_err_code = byte; /* for BIOS display message */ + asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST; + return ADV_ERROR; + } + + /* We need to reset back to normal mode after LRAM test passes. */ + AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); + + /* + * Load the Microcode + * + * Write the microcode image to RISC memory starting at address 0. + * + */ + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + + /* Assume the following compressed format of the microcode buffer: + * + * 254 word (508 byte) table indexed by byte code followed + * by the following byte codes: + * + * 1-Byte Code: + * 00: Emit word 0 in table. + * 01: Emit word 1 in table. + * . + * FD: Emit word 253 in table. + * + * Multi-Byte Code: + * FE WW WW: (3 byte code) Word to emit is the next word WW WW. + * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. + */ + word = 0; + for (i = 253 * 2; i < _adv_asc38C0800_size; i++) + { + if (_adv_asc38C0800_buf[i] == 0xff) + { + for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) + { + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc38C0800_buf[i + 3] << 8) | + _adv_asc38C0800_buf[i + 2])); + word++; + } + i += 3; + } else if (_adv_asc38C0800_buf[i] == 0xfe) + { + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc38C0800_buf[i + 2] << 8) | + _adv_asc38C0800_buf[i + 1])); i += 2; word++; } else { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | - _adv_asc3550_buf[_adv_asc3550_buf[i] * 2])); + _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | + _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2])); word++; } } @@ -15839,12 +15843,12 @@ * the expanded mcode size. */ word *= 2; - adv_asc3550_expanded_size = word; + adv_asc38C0800_expanded_size = word; /* - * Clear the rest of ASC-3550 Internal RAM (8KB). + * Clear the rest of ASC-38C0800 Internal RAM (16KB). */ - for (; word < ADV_3550_MEMSIZE; word += 2) + for (; word < ADV_38C0800_MEMSIZE; word += 2) { AdvWriteWordAutoIncLram(iop_base, 0); } @@ -15855,12 +15859,17 @@ sum = 0; AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - for (word = 0; word < adv_asc3550_expanded_size; word += 2) + for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) { sum += AdvReadWordAutoIncLram(iop_base); } + ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i); - if (sum != _adv_asc3550_chksum) + ASC_DBG2(1, + "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n", + (ulong) sum, (ulong) _adv_asc38C0800_chksum); + + if (sum != _adv_asc38C0800_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return ADV_ERROR; @@ -15871,7 +15880,7 @@ */ for (i = 0; i < ASC_MC_BIOSLEN/2; i++) { - AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); + AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]); } /* @@ -15889,15 +15898,26 @@ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); /* - * Read and save microcode version and date. + * Read microcode version and date. */ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); /* - * Set the chip type to indicate the ASC3550. + * Set the chip type to indicate the ASC38C0800. */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); + + /* + * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. + * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current + * cable detection and then we are able to read C_DET[3:0]. + * + * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 + * Microcode Default Value' section below. + */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV); /* * If the PCI Configuration Command Register "Parity Error Response @@ -15907,22 +15927,21 @@ */ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); word |= CONTROL_FLAG_IGNORE_PERR; AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); } /* - * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO - * threshold of 128 bytes. This register is only accessible to the host. + * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] + * bits for the default FIFO threshold. + * + * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. + * + * For DMA Errata #4 set the BC_THRESH_ENB bit. */ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - START_CTL_EMFU | READ_CMD_MRM); + BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); /* * Microcode operating variables for WDTR, SDTR, and command tag @@ -15943,63 +15962,19 @@ } /* - * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID - * bitmask. These values determine the maximum SDTR speed negotiated - * with a device. + * Set microcode operating variables for DISC and SDTR_SPEED1, + * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM + * configuration values. * * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them * without determining here whether the device supports SDTR. - * - * 4-bit speed SDTR speed name - * =========== =============== - * 0000b (0x0) SDTR disabled - * 0001b (0x1) 5 Mhz - * 0010b (0x2) 10 Mhz - * 0011b (0x3) 20 Mhz (Ultra) - * 0100b (0x4) 40 Mhz (LVD/Ultra2) - * 0101b (0x5) 80 Mhz (LVD2/Ultra3) - * 0110b (0x6) Undefined - * . - * 1111b (0xF) Undefined - */ - word = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) - { - if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) - { - /* Set Ultra speed for TID 'tid'. */ - word |= (0x3 << (4 * (tid % 4))); - } else - { - /* Set Fast speed for TID 'tid'. */ - word |= (0x2 << (4 * (tid % 4))); - } - if (tid == 3) /* Check if done with sdtr_speed1. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); - word = 0; - } else if (tid == 7) /* Check if done with sdtr_speed2. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); - word = 0; - } else if (tid == 11) /* Check if done with sdtr_speed3. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); - word = 0; - } else if (tid == 15) /* Check if done with sdtr_speed4. */ - { - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); - /* End of loop. */ - } - } - - /* - * Set microcode operating variable for the disconnect per TID bitmask. */ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); - + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); + AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); /* * Set SCSI_CFG0 Microcode Default Value. @@ -16008,7 +15983,8 @@ * after it is started below. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); /* * Determine SCSI_CFG1 Microcode Default Value. @@ -16021,16 +15997,6 @@ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); /* - * If all three connectors are in use, return an error. - */ - if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || - (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) - { - asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; - return ADV_ERROR; - } - - /* * If the internal narrow cable is reversed all of the SCSI_CTRL * register signals will be set. Check for and return an error if * this condition is found. @@ -16042,73 +16008,88 @@ } /* - * If this is a differential board and a single-ended device - * is attached to one of the connectors, return an error. + * All kind of combinations of devices attached to one of four connectors + * are acceptable except HVD device attached. For example, LVD device can + * be attached to SE connector while SE device attached to LVD connector. + * If LVD device attached to SE connector, it only runs up to Ultra speed. + * + * If an HVD device is attached to one of LVD connectors, return an error. + * However, there is no way to detect HVD device attached to SE connectors. */ - if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) + if (scsi_cfg1 & HVD) { - asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; return ADV_ERROR; } /* - * If automatic termination control is enabled, then set the - * termination value based on a table listed in a_condor.h. + * If either SE or LVD automatic termination control is enabled, then + * set the termination value based on a table listed in a_condor.h. * - * If manual termination was specified with an EEPROM setting - * then 'termination' was set-up in AdvInitFrom3550EEPROM() and - * is ready to be 'ored' into SCSI_CFG1. + * If manual termination was specified with an EEPROM setting then + * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to + * be 'ored' into SCSI_CFG1. */ - if (asc_dvc->cfg->termination == 0) + if ((asc_dvc->cfg->termination & TERM_SE) == 0) { - /* - * The software always controls termination by setting TERM_CTL_SEL. - * If TERM_CTL_SEL were set to 0, the hardware would set termination. - */ - asc_dvc->cfg->termination |= TERM_CTL_SEL; - - switch(scsi_cfg1 & CABLE_DETECT) + /* SE automatic termination control is enabled. */ + switch(scsi_cfg1 & C_DET_SE) { - /* TERM_CTL_H: on, TERM_CTL_L: on */ - case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF: - asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + /* TERM_SE_HI: on, TERM_SE_LO: on */ + case 0x1: case 0x2: case 0x3: + asc_dvc->cfg->termination |= TERM_SE; break; - /* TERM_CTL_H: on, TERM_CTL_L: off */ - case 0x1: case 0x5: case 0x9: case 0xA: case 0xC: - asc_dvc->cfg->termination |= TERM_CTL_H; + /* TERM_SE_HI: on, TERM_SE_LO: off */ + case 0x0: + asc_dvc->cfg->termination |= TERM_SE_HI; break; + } + } - /* TERM_CTL_H: off, TERM_CTL_L: off */ - case 0x2: case 0x6: + if ((asc_dvc->cfg->termination & TERM_LVD) == 0) + { + /* LVD automatic termination control is enabled. */ + switch(scsi_cfg1 & C_DET_LVD) + { + /* TERM_LVD_HI: on, TERM_LVD_LO: on */ + case 0x4: case 0x8: case 0xC: + asc_dvc->cfg->termination |= TERM_LVD; + break; + + /* TERM_LVD_HI: off, TERM_LVD_LO: off */ + case 0x0: break; } } /* - * Clear any set TERM_CTL_H and TERM_CTL_L bits. + * Clear any set TERM_SE and TERM_LVD bits. */ - scsi_cfg1 &= ~TERM_CTL; + scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); /* - * Invert the TERM_CTL_H and TERM_CTL_L bits and then - * set 'scsi_cfg1'. The TERM_POL bit does not need to be - * referenced, because the hardware internally inverts - * the Termination High and Low bits if TERM_POL is set. + * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. */ - scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); + + /* + * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits + * and set possibly modified termination control bits in the Microcode + * SCSI_CFG1 Register Value. + */ + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); /* * Set SCSI_CFG1 Microcode Default Value * - * Set filter value and possibly modified termination control + * Set possibly modified termination control and reset DIS_TERM_DRV * bits in the Microcode SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, - FLTR_DISABLE | scsi_cfg1); + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); /* * Set MEM_CFG Microcode Default Value @@ -16119,10 +16100,10 @@ * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * - * ASC-3550 has 8KB internal memory. + * ASC-38C0800 has 16KB internal memory. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_8KB); + BIOS_EN | RAM_SZ_16KB); /* * Set SEL_MASK Microcode Default Value @@ -16134,7 +16115,7 @@ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); /* - * Build carrier freelist. + * Build the carrier freelist. * * Driver must have already allocated memory and set 'carrier_buf'. */ @@ -16152,7 +16133,7 @@ do { /* - * Get physical address of the carrier 'carrp'. + * Get physical address for the carrier 'carrp'. */ contig_len = sizeof(ADV_CARR_T); carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp, @@ -16172,12 +16153,12 @@ } carrp->carr_pa = carr_paddr; - carrp->carr_va = ADV_VADDR_TO_U32(carrp); + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); /* * Insert the carrier at the beginning of the freelist. */ - carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist); + carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); asc_dvc->carr_freelist = carrp; carrp++; @@ -16193,19 +16174,19 @@ asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); /* * The first command issued will be placed in the stopper carrier. */ - asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Set RISC ICQ physical address start value. + * carr_pa is LE, must be native before write */ - AdvWriteDWordLram(iop_base, ASC_MC_ICQ, - cpu_to_le32(asc_dvc->icq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); /* * Set-up the RISC->Host Initiator Response Queue (IRQ). @@ -16215,8 +16196,8 @@ asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); /* * The first command completed by the RISC will be placed in @@ -16225,23 +16206,19 @@ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is * completed the RISC will set the ASC_RQ_STOPPER bit. */ - asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Set RISC IRQ physical address start value. + * + * carr_pa is LE, must be native before write * */ - AdvWriteDWordLram(iop_base, ASC_MC_IRQ, - cpu_to_le32(asc_dvc->irq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); asc_dvc->carr_pending_cnt = 0; AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); AdvWriteWordRegister(iop_base, IOPW_PC, word); @@ -16286,15 +16263,17 @@ } /* - * Initialize the ASC-38C0800. + * Initialize the ASC-38C1600. * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. + * + * Needed after initialization for error recovery. */ STATIC int -AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) +AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) { AdvPortAddr iop_base; ushort warn_code; @@ -16302,9 +16281,9 @@ int begin_addr; int end_addr; ushort code_sum; - int word; + long word; int j; - int adv_asc38C0800_expanded_size; + int adv_asc38C1600_expanded_size; ADV_CARR_T *carrp; ADV_DCNT contig_len; ADV_SDCNT buf_size; @@ -16314,8 +16293,8 @@ uchar byte; uchar tid; ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able, sdtr_able, tagqng_able; - uchar max_cmd[ADV_MAX_TID + 1]; + ushort wdtr_able, sdtr_able, ppr_able, tagqng_able; + uchar max_cmd[ASC_MAX_TID + 1]; /* If there is already an error, don't continue. */ if (asc_dvc->err_code != 0) @@ -16324,9 +16303,9 @@ } /* - * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. + * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600. */ - if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) + if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; return ADV_ERROR; @@ -16353,15 +16332,16 @@ */ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) + for (tid = 0; tid <= ASC_MAX_TID; tid++) { AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, max_cmd[tid]); } /* - * RAM BIST (RAM Built-In Self Test) + * RAM BIST (Built-In Self Test) * * Address : I/O base + offset 0x38h register (byte). * Function: Bit 7-6(RW) : RAM mode @@ -16440,7 +16420,8 @@ */ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - /* Assume the following compressed format of the microcode buffer: + /* + * Assume the following compressed format of the microcode buffer: * * 254 word (508 byte) table indexed by byte code followed * by the following byte codes: @@ -16456,30 +16437,30 @@ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. */ word = 0; - for (i = 253 * 2; i < _adv_asc38C0800_size; i++) + for (i = 253 * 2; i < _adv_asc38C1600_size; i++) { - if (_adv_asc38C0800_buf[i] == 0xff) + if (_adv_asc38C1600_buf[i] == 0xff) { - for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) + for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[i + 3] << 8) | - _adv_asc38C0800_buf[i + 2])); + _adv_asc38C1600_buf[i + 3] << 8) | + _adv_asc38C1600_buf[i + 2])); word++; } - i += 3; - } else if (_adv_asc38C0800_buf[i] == 0xfe) + i += 3; + } else if (_adv_asc38C1600_buf[i] == 0xfe) { - AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[i + 2] << 8) | - _adv_asc38C0800_buf[i + 1])); + AdvWriteWordAutoIncLram(iop_base, (((ushort) + _adv_asc38C1600_buf[i + 2] << 8) | + _adv_asc38C1600_buf[i + 1])); i += 2; word++; } else { AdvWriteWordAutoIncLram(iop_base, (((ushort) - _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | - _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2])); + _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | + _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2])); word++; } } @@ -16489,12 +16470,12 @@ * the expanded mcode size. */ word *= 2; - adv_asc38C0800_expanded_size = word; + adv_asc38C1600_expanded_size = word; /* - * Clear the rest of ASC-38C0800 Internal RAM (16KB). + * Clear the rest of ASC-38C1600 Internal RAM (32KB). */ - for (; word < ADV_38C0800_MEMSIZE; word += 2) + for (; word < ADV_38C1600_MEMSIZE; word += 2) { AdvWriteWordAutoIncLram(iop_base, 0); } @@ -16505,17 +16486,12 @@ sum = 0; AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) + for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) { sum += AdvReadWordAutoIncLram(iop_base); } - ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i); - - ASC_DBG2(1, - "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n", - (ulong) sum, (ulong) _adv_asc38C0800_chksum); - if (sum != _adv_asc38C0800_chksum) + if (sum != _adv_asc38C1600_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return ADV_ERROR; @@ -16550,9 +16526,9 @@ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); /* - * Set the chip type to indicate the ASC38C0800. + * Set the chip type to indicate the ASC38C1600. */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); + AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600); /* * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. @@ -16573,26 +16549,30 @@ */ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); word |= CONTROL_FLAG_IGNORE_PERR; AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); } /* - * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] - * bits for the default FIFO threshold. - * - * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. - * - * For DMA Errata #4 set the BC_THRESH_ENB bit. + * If the BIOS control flag AIPP (Asynchronous Information + * Phase Protection) disable bit is not set, then set the firmware + * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable + * AIPP checking and encoding. + */ + if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) + { + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_ENABLE_AIPP; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4], + * and START_CTL_TH [3:2]. */ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); + FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); /* * Microcode operating variables for WDTR, SDTR, and command tag @@ -16634,22 +16614,24 @@ * after it is started below. */ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | + asc_dvc->chip_scsi_id); /* - * Determine SCSI_CFG1 Microcode Default Value. + * Calculate SCSI_CFG1 Microcode Default Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. + * + * Each ASC-38C1600 function has only two cable detect bits. + * The bus mode override bits are in IOPB_SOFT_OVER_WR. */ - - /* Read current SCSI_CFG1 Register value. */ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); /* - * If the internal narrow cable is reversed all of the SCSI_CTRL - * register signals will be set. Check for and return an error if - * this condition is found. + * If the cable is reversed all of the SCSI_CTRL register signals + * will be set. Check for and return an error if this condition is + * found. */ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { @@ -16658,13 +16640,12 @@ } /* - * All kind of combinations of devices attached to one of four connectors - * are acceptable except HVD device attached. For example, LVD device can - * be attached to SE connector while SE device attached to LVD connector. - * If LVD device attached to SE connector, it only runs up to Ultra speed. + * Each ASC-38C1600 function has two connectors. Only an HVD device + * can not be connected to either connector. An LVD device or SE device + * may be connected to either connecor. If an SE device is connected, + * then at most Ultra speed (20 Mhz) can be used on both connectors. * - * If an HVD device is attached to one of LVD connectors, return an error. - * However, there is no way to detect HVD device attached to SE connectors. + * If an HVD device is attached, return an error. */ if (scsi_cfg1 & HVD) { @@ -16673,12 +16654,17 @@ } /* - * If either SE or LVD automatic termination control is enabled, then - * set the termination value based on a table listed in a_condor.h. + * Each function in the ASC-38C1600 uses only the SE cable detect and + * termination because there are two connectors for each function. Each + * function may use either LVD or SE mode. Corresponding the SE automatic + * termination control EEPROM bits are used for each function. Each + * function has its own EEPROM. If SE automatic control is enabled for + * the function, then set the termination value based on a table listed + * in a_condor.h. * - * If manual termination was specified with an EEPROM setting then - * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to - * be 'ored' into SCSI_CFG1. + * If manual termination is specified in the EEPROM for the function, + * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is + * ready to be 'ored' into SCSI_CFG1. */ if ((asc_dvc->cfg->termination & TERM_SE) == 0) { @@ -16690,51 +16676,44 @@ asc_dvc->cfg->termination |= TERM_SE; break; - /* TERM_SE_HI: on, TERM_SE_LO: off */ - case 0x0: - asc_dvc->cfg->termination |= TERM_SE_HI; - break; - } - } - - if ((asc_dvc->cfg->termination & TERM_LVD) == 0) - { - /* LVD automatic termination control is enabled. */ - switch(scsi_cfg1 & C_DET_LVD) - { - /* TERM_LVD_HI: on, TERM_LVD_LO: on */ - case 0x4: case 0x8: case 0xC: - asc_dvc->cfg->termination |= TERM_LVD; - break; - - /* TERM_LVD_HI: off, TERM_LVD_LO: off */ case 0x0: + if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) + { + /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */ + } + else + { + /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */ + asc_dvc->cfg->termination |= TERM_SE_HI; + } break; } } /* - * Clear any set TERM_SE and TERM_LVD bits. + * Clear any set TERM_SE bits. */ - scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); + scsi_cfg1 &= ~TERM_SE; /* - * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. + * Invert the TERM_SE bits and then set 'scsi_cfg1'. */ - scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); + scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE); /* - * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits - * and set possibly modified termination control bits in the Microcode - * SCSI_CFG1 Register Value. + * Clear Big Endian and Terminator Polarity bits and set possibly + * modified termination control bits in the Microcode SCSI_CFG1 + * Register Value. + * + * Big Endian bit is not used even on big endian machines. */ - scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); + scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL); /* * Set SCSI_CFG1 Microcode Default Value * - * Set possibly modified termination control and reset DIS_TERM_DRV - * bits in the Microcode SCSI_CFG1 Register Value. + * Set possibly modified termination control bits in the Microcode + * SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. @@ -16750,10 +16729,17 @@ * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * - * ASC-38C0800 has 16KB internal memory. + * ASC-38C1600 has 32KB internal memory. + * + * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come + * out a special 16K Adv Library and Microcode version. After the issue + * resolved, we should turn back to the 32K support. Both a_condor.h and + * mcode.sas files also need to be updated. + * + * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, + * BIOS_EN | RAM_SZ_32KB); */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_16KB); + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, BIOS_EN | RAM_SZ_16KB); /* * Set SEL_MASK Microcode Default Value @@ -16769,6 +16755,7 @@ * * Driver must have already allocated memory and set 'carrier_buf'. */ + ASC_ASSERT(asc_dvc->carrier_buf != NULL); carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); @@ -16803,12 +16790,12 @@ } carrp->carr_pa = carr_paddr; - carrp->carr_va = ADV_VADDR_TO_U32(carrp); + carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); /* * Insert the carrier at the beginning of the freelist. */ - carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist); + carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); asc_dvc->carr_freelist = carrp; carrp++; @@ -16818,25 +16805,27 @@ /* * Set-up the Host->RISC Initiator Command Queue (ICQ). */ - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); /* * The first command issued will be placed in the stopper carrier. */ - asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* - * Set RISC ICQ physical address start value. + * Set RISC ICQ physical address start value. Initialize the + * COMMA register to the same value otherwise the RISC will + * prematurely detect a command is available. */ - AdvWriteDWordLram(iop_base, ASC_MC_ICQ, - cpu_to_le32(asc_dvc->icq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); + AdvWriteDWordRegister(iop_base, IOPDW_COMMA, + le32_to_cpu(asc_dvc->icq_sp->carr_pa)); /* * Set-up the RISC->Host Initiator Response Queue (IRQ). @@ -16846,8 +16835,8 @@ asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); /* * The first command completed by the RISC will be placed in @@ -16856,22 +16845,16 @@ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is * completed the RISC will set the ASC_RQ_STOPPER bit. */ - asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER; + asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Set RISC IRQ physical address start value. */ - AdvWriteDWordLram(iop_base, ASC_MC_IRQ, - cpu_to_le32(asc_dvc->irq_sp->carr_pa)); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); asc_dvc->carr_pending_cnt = 0; AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); - /* - * Note: Don't remove the use of a temporary variable in - * the following code, otherwise the Microsoft C compiler - * will turn the following lines into a no-op. - */ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); AdvWriteWordRegister(iop_base, IOPW_PC, word); @@ -16887,8 +16870,7 @@ { /* * If the BIOS Signature is present in memory, restore the - * BIOS Handshake Configuration Table and do not perform - * a SCSI Bus Reset. + * per TID microcode operating variables. */ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA) { @@ -16897,8 +16879,9 @@ */ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) + for (tid = 0; tid <= ASC_MAX_TID; tid++) { AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, max_cmd[tid]); @@ -16945,8 +16928,6 @@ * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found. - * - * XXX - Don't handle big-endian access to EEPROM yet. */ if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { @@ -16967,13 +16948,13 @@ * failed. */ eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); AdvSet3550EEPConfig(iop_base, &eep_config); } @@ -17049,7 +17030,211 @@ asc_dvc->max_host_qng = eep_config.max_host_qng; asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - + + /* + * If the EEPROM 'termination' field is set to automatic (0), then set + * the ADV_DVC_CFG 'termination' field to automatic also. + * + * If the termination is specified with a non-zero 'termination' + * value check that a legal value is set and set the ADV_DVC_CFG + * 'termination' field appropriately. + */ + if (eep_config.termination == 0) + { + asc_dvc->cfg->termination = 0; /* auto termination */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination == 1) + { + asc_dvc->cfg->termination = TERM_CTL_SEL; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination == 2) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination == 3) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; + } else + { + /* + * The EEPROM 'termination' field contains a bad value. Use + * automatic termination instead. + */ + asc_dvc->cfg->termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + return warn_code; +} + +/* + * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and + * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * all of this is done. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Note: Chip is stopped on entry. + */ +ASC_INITFUNC( +STATIC int, +AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADVEEP_38C0800_CONFIG eep_config; + int i; + uchar tid, termination; + ushort sdtr_speed = 0; + + iop_base = asc_dvc->iop_base; + + warn_code = 0; + + /* + * Read the board's EEPROM configuration. + * + * Set default values if a bad checksum is found. + */ + if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum) + { + warn_code |= ASC_WARN_EEPROM_CHKSUM; + + /* + * Set EEPROM default values. + */ + for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_38C0800_EEPROM_Config + i); + } + + /* + * Assume the 6 byte board serial number that was read + * from EEPROM is correct even if the EEPROM checksum + * failed. + */ + eep_config.serial_number_word3 = + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); + + eep_config.serial_number_word2 = + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); + + eep_config.serial_number_word1 = + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); + + AdvSet38C0800EEPConfig(iop_base, &eep_config); + } + /* + * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * EEPROM configuration that was read. + * + * This is the mapping of EEPROM fields to Adv Library fields. + */ + asc_dvc->wdtr_able = eep_config.wdtr_able; + asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1; + asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; + asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; + asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; + asc_dvc->tagqng_able = eep_config.tagqng_able; + asc_dvc->cfg->disc_enable = eep_config.disc_enable; + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->start_motor = eep_config.start_motor; + asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; + asc_dvc->bios_ctrl = eep_config.bios_ctrl; + asc_dvc->no_scam = eep_config.scam_tolerant; + asc_dvc->cfg->serial1 = eep_config.serial_number_word1; + asc_dvc->cfg->serial2 = eep_config.serial_number_word2; + asc_dvc->cfg->serial3 = eep_config.serial_number_word3; + + /* + * For every Target ID if any of its 'sdtr_speed[1234]' bits + * are set, then set an 'sdtr_able' bit for it. + */ + asc_dvc->sdtr_able = 0; + for (tid = 0; tid <= ADV_MAX_TID; tid++) + { + if (tid == 0) + { + sdtr_speed = asc_dvc->sdtr_speed1; + } else if (tid == 4) + { + sdtr_speed = asc_dvc->sdtr_speed2; + } else if (tid == 8) + { + sdtr_speed = asc_dvc->sdtr_speed3; + } else if (tid == 12) + { + sdtr_speed = asc_dvc->sdtr_speed4; + } + if (sdtr_speed & ADV_MAX_TID) + { + asc_dvc->sdtr_able |= (1 << tid); + } + sdtr_speed >>= 4; + } + + /* + * Set the host maximum queuing (max. 253, min. 16) and the per device + * maximum queuing (max. 63, min. 4). + */ + if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_host_qng == 0) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else + { + eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; + } + } + + if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_dvc_qng == 0) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else + { + eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; + } + } + + /* + * If 'max_dvc_qng' is greater than 'max_host_qng', then + * set 'max_dvc_qng' to 'max_host_qng'. + */ + if (eep_config.max_dvc_qng > eep_config.max_host_qng) + { + eep_config.max_dvc_qng = eep_config.max_host_qng; + } + + /* + * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' + * values based on possibly adjusted EEPROM values. + */ + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + /* * If the EEPROM 'termination' field is set to automatic (0), then set * the ADV_DVC_CFG 'termination' field to automatic also. @@ -17058,32 +17243,63 @@ * value check that a legal value is set and set the ADV_DVC_CFG * 'termination' field appropriately. */ - if (eep_config.termination == 0) + if (eep_config.termination_se == 0) { - asc_dvc->cfg->termination = 0; /* auto termination */ + termination = 0; /* auto termination for SE */ } else { /* Enable manual control with low off / high off. */ - if (eep_config.termination == 1) + if (eep_config.termination_se == 1) { - asc_dvc->cfg->termination = TERM_CTL_SEL; + termination = 0; /* Enable manual control with low off / high on. */ - } else if (eep_config.termination == 2) + } else if (eep_config.termination_se == 2) { - asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; + termination = TERM_SE_HI; /* Enable manual control with low on / high on. */ - } else if (eep_config.termination == 3) + } else if (eep_config.termination_se == 3) { - asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; + termination = TERM_SE; } else { /* - * The EEPROM 'termination' field contains a bad value. Use - * automatic termination instead. + * The EEPROM 'termination_se' field contains a bad value. + * Use automatic termination instead. */ - asc_dvc->cfg->termination = 0; + termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + if (eep_config.termination_lvd == 0) + { + asc_dvc->cfg->termination = termination; /* auto termination for LVD */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination_lvd == 1) + { + asc_dvc->cfg->termination = termination; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination_lvd == 2) + { + asc_dvc->cfg->termination = termination | TERM_LVD_HI; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination_lvd == 3) + { + asc_dvc->cfg->termination = + termination | TERM_LVD; + } else + { + /* + * The EEPROM 'termination_lvd' field contains a bad value. + * Use automatic termination instead. + */ + asc_dvc->cfg->termination = termination; warn_code |= ASC_WARN_EEPROM_TERMINATION; } } @@ -17092,11 +17308,11 @@ } /* - * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and - * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and + * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while * all of this is done. * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. @@ -17105,12 +17321,12 @@ */ ASC_INITFUNC( STATIC int, -AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) +AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) ) { AdvPortAddr iop_base; ushort warn_code; - ADVEEP_38C0800_CONFIG eep_config; + ADVEEP_38C1600_CONFIG eep_config; int i; uchar tid, termination; ushort sdtr_speed = 0; @@ -17123,20 +17339,59 @@ * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found. - * - * XXX - Don't handle big-endian access to EEPROM yet. */ - if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum) + if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { warn_code |= ASC_WARN_EEPROM_CHKSUM; /* * Set EEPROM default values. */ - for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) + for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) { - *((uchar *) &eep_config + i) = - *((uchar *) &Default_38C0800_EEPROM_Config + i); + if (i == 1 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != 0) + { + /* + * Set Function 1 EEPROM Word 0 MSB + * + * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11) + * EEPROM bits. + * + * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and + * old Mac system booting problem. The Expansion ROM must + * be disabled in Function 1 for these systems. + * + */ + *((uchar *) &eep_config + i) = + ((*((uchar *) &Default_38C1600_EEPROM_Config + i)) & + (~(((ADV_EEPROM_BIOS_ENABLE | ADV_EEPROM_INTAB) >> 8) & + 0xFF))); + + /* + * Set the INTAB (bit 11) if the GPIO 0 input indicates + * the Function 1 interrupt line is wired to INTA. + * + * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input: + * 1 - Function 1 interrupt line wired to INT A. + * 0 - Function 1 interrupt line wired to INT B. + * + * Note: Adapter boards always have Function 0 wired to INTA. + * Put all 5 GPIO bits in input mode and then read + * their input values. + */ + AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0); + if (AdvReadByteRegister(iop_base, IOPB_GPIO_DATA) & 0x01) + { + /* Function 1 interrupt wired to INTA; Set EEPROM bit. */ + *((uchar *) &eep_config + i) |= + ((ADV_EEPROM_INTAB >> 8) & 0xFF); + } + } + else + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_38C1600_EEPROM_Config + i); + } } /* @@ -17145,18 +17400,19 @@ * failed. */ eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); - AdvSet38C0800EEPConfig(iop_base, &eep_config); + AdvSet38C1600EEPConfig(iop_base, &eep_config); } + /* - * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the * EEPROM configuration that was read. * * This is the mapping of EEPROM fields to Adv Library fields. @@ -17166,25 +17422,23 @@ asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; + asc_dvc->ppr_able = 0; asc_dvc->tagqng_able = eep_config.tagqng_able; asc_dvc->cfg->disc_enable = eep_config.disc_enable; asc_dvc->max_host_qng = eep_config.max_host_qng; asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID); asc_dvc->start_motor = eep_config.start_motor; asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; asc_dvc->bios_ctrl = eep_config.bios_ctrl; asc_dvc->no_scam = eep_config.scam_tolerant; - asc_dvc->cfg->serial1 = eep_config.serial_number_word1; - asc_dvc->cfg->serial2 = eep_config.serial_number_word2; - asc_dvc->cfg->serial3 = eep_config.serial_number_word3; /* * For every Target ID if any of its 'sdtr_speed[1234]' bits * are set, then set an 'sdtr_able' bit for it. */ asc_dvc->sdtr_able = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) + for (tid = 0; tid <= ASC_MAX_TID; tid++) { if (tid == 0) { @@ -17199,7 +17453,7 @@ { sdtr_speed = asc_dvc->sdtr_speed4; } - if (sdtr_speed & ADV_MAX_TID) + if (sdtr_speed & ASC_MAX_TID) { asc_dvc->sdtr_able |= (1 << tid); } @@ -17250,7 +17504,7 @@ } /* - * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' + * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng' * values based on possibly adjusted EEPROM values. */ asc_dvc->max_host_qng = eep_config.max_host_qng; @@ -17258,10 +17512,10 @@ /* * If the EEPROM 'termination' field is set to automatic (0), then set - * the ADV_DVC_CFG 'termination' field to automatic also. + * the ASC_DVC_CFG 'termination' field to automatic also. * * If the termination is specified with a non-zero 'termination' - * value check that a legal value is set and set the ADV_DVC_CFG + * value check that a legal value is set and set the ASC_DVC_CFG * 'termination' field appropriately. */ if (eep_config.termination_se == 0) @@ -17341,25 +17595,37 @@ ushort wval, chksum; ushort *wbuf; int eep_addr; + ushort *charfields; + charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar; wbuf = (ushort *) cfg_buf; chksum = 0; - for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; - eep_addr < ASC_EEP_DVC_CFG_END; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; - *wbuf = wval; + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; + } } + /* Read checksum word. */ *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; - eep_addr < ASC_EEP_MAX_WORD_ADDR; + wbuf++; charfields++; + + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } } return chksum; } @@ -17378,29 +17644,89 @@ ushort wval, chksum; ushort *wbuf; int eep_addr; + ushort *charfields; + charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar; wbuf = (ushort *) cfg_buf; chksum = 0; - for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; - eep_addr < ASC_EEP_DVC_CFG_END; + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; - *wbuf = wval; + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; + } } + /* Read checksum word. */ *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; - eep_addr < ASC_EEP_MAX_WORD_ADDR; + wbuf++; charfields++; + + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } } return chksum; } +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +ASC_INITFUNC( +STATIC ushort, +AdvGet38C1600EEPConfig(AdvPortAddr iop_base, + ADVEEP_38C1600_CONFIG *cfg_buf) +) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + ushort *charfields; + + charfields = (ushort*) &ADVEEP_38C1600_Config_Field_IsChar; + wbuf = (ushort *) cfg_buf; + chksum = 0; + + for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; + eep_addr < ADV_EEP_DVC_CFG_END; + eep_addr++, wbuf++) + { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; /* Checksum is calculated from word values. */ + if (*charfields++) { + *wbuf = le16_to_cpu(wval); + } else { + *wbuf = wval; + } + } + /* Read checksum word. */ + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; charfields++; + + /* Read rest of EEPROM not covered by the checksum. */ + for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; + eep_addr < ADV_EEP_MAX_WORD_ADDR; + eep_addr++, wbuf++) + { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + if (*charfields++) { + *wbuf = le16_to_cpu(*wbuf); + } + } + return chksum; +} /* * Read the EEPROM from specified location @@ -17426,7 +17752,7 @@ { int eep_delay_ms; - for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++) + for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) { if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) { @@ -17449,41 +17775,57 @@ { ushort *wbuf; ushort addr, chksum; + ushort *charfields; wbuf = (ushort *) cfg_buf; + charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar; chksum = 0; AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); AdvWaitEEPCmd(iop_base); /* - * Write EEPROM from word 0 to word 20 + * Write EEPROM from word 0 to word 20. */ - for (addr = ASC_EEP_DVC_CFG_BEGIN; - addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - chksum += *wbuf; - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + DvcSleepMilliSecond(ADV_EEP_DELAY_MS); } /* - * Write EEPROM checksum at word 21 + * Write EEPROM checksum at word 21. */ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - wbuf++; /* skip over check_sum */ + wbuf++; charfields++; /* - * Write EEPROM OEM name at words 22 to 29 + * Write EEPROM OEM name at words 22 to 29. */ - for (addr = ASC_EEP_DVC_CTL_BEGIN; - addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); } @@ -17500,42 +17842,126 @@ ADVEEP_38C0800_CONFIG *cfg_buf) { ushort *wbuf; + ushort *charfields; ushort addr, chksum; wbuf = (ushort *) cfg_buf; + charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar; + chksum = 0; + + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); + + /* + * Write EEPROM from word 0 to word 20. + */ + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) + { + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + DvcSleepMilliSecond(ADV_EEP_DELAY_MS); + } + + /* + * Write EEPROM checksum at word 21. + */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; charfields++; + + /* + * Write EEPROM OEM name at words 22 to 29. + */ + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) + { + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); + return; +} + +/* + * Write the EEPROM from 'cfg_buf'. + */ +void +AdvSet38C1600EEPConfig(AdvPortAddr iop_base, + ADVEEP_38C1600_CONFIG *cfg_buf) +{ + ushort *wbuf; + ushort *charfields; + ushort addr, chksum; + + wbuf = (ushort *) cfg_buf; + charfields = (ushort *) &ADVEEP_38C1600_Config_Field_IsChar; chksum = 0; AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); AdvWaitEEPCmd(iop_base); /* - * Write EEPROM from word 0 to word 20 + * Write EEPROM from word 0 to word 20. */ - for (addr = ASC_EEP_DVC_CFG_BEGIN; - addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CFG_BEGIN; + addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - chksum += *wbuf; - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + chksum += *wbuf; /* Checksum is calculated from word values. */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + DvcSleepMilliSecond(ADV_EEP_DELAY_MS); } /* - * Write EEPROM checksum at word 21 + * Write EEPROM checksum at word 21. */ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); - wbuf++; /* skip over check_sum */ + wbuf++; charfields++; /* - * Write EEPROM OEM name at words 22 to 29 + * Write EEPROM OEM name at words 22 to 29. */ - for (addr = ASC_EEP_DVC_CTL_BEGIN; - addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + for (addr = ADV_EEP_DVC_CTL_BEGIN; + addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + ushort word; + + if (*charfields++) { + word = cpu_to_le16(*wbuf); + } else { + word = *wbuf; + } + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); AdvWaitEEPCmd(iop_base); } @@ -17570,7 +17996,7 @@ AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq) { - int last_int_level; + ulong last_int_level; AdvPortAddr iop_base; ADV_DCNT req_size; ADV_PADDR req_paddr; @@ -17598,10 +18024,11 @@ */ if ((new_carrp = asc_dvc->carr_freelist) == NULL) { + DvcLeaveCritical(last_int_level); return ADV_BUSY; } - asc_dvc->carr_freelist = - (ADV_CARR_T *) ADV_U32_TO_VADDR(new_carrp->next_vpa); + asc_dvc->carr_freelist = (ADV_CARR_T *) + ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa)); asc_dvc->carr_pending_cnt++; /* @@ -17609,7 +18036,7 @@ * to the stopper value. The current stopper will be changed * below to point to the new stopper. */ - new_carrp->next_vpa = ASC_CQ_STOPPER; + new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); /* * Clear the ADV_SCSI_REQ_Q done flag. @@ -17617,17 +18044,20 @@ scsiq->a_flag &= ~ADV_SCSIQ_DONE; req_size = sizeof(ADV_SCSI_REQ_Q); - req_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq, - (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG)); + req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq, + (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG); - ASC_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr); + ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr); ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); + /* Wait for assertion before making little-endian */ + req_paddr = cpu_to_le32(req_paddr); + /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */ - scsiq->scsiq_ptr = ADV_VADDR_TO_U32(scsiq); + scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq)); scsiq->scsiq_rptr = req_paddr; - scsiq->carr_va = ADV_VADDR_TO_U32(asc_dvc->icq_sp); + scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp)); /* * Every ADV_CARR_T.carr_pa is byte swapped to little-endian * order during initialization. @@ -17653,18 +18083,30 @@ */ asc_dvc->icq_sp = new_carrp; - /* - * Tickle the RISC to tell it to read its Command Queue Head pointer. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || + asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { /* - * Clear the tickle value. In the ASC-3550 the RISC flag - * command 'clr_tickle_a' does not work unless the host - * value is cleared. + * Tickle the RISC to tell it to read its Command Queue Head pointer. */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + { + /* + * Clear the tickle value. In the ASC-3550 the RISC flag + * command 'clr_tickle_a' does not work unless the host + * value is cleared. + */ + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + } + } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + /* + * Notify the RISC a carrier is ready by writing the physical + * address of the new carrier stopper to the COMMA register. + */ + AdvWriteDWordRegister(iop_base, IOPDW_COMMA, + le32_to_cpu(new_carrp->carr_pa)); } DvcLeaveCritical(last_int_level); @@ -17731,6 +18173,7 @@ { int status; ushort wdtr_able, sdtr_able, tagqng_able; + ushort ppr_able = 0; uchar tid, max_cmd[ADV_MAX_TID + 1]; AdvPortAddr iop_base; ushort bios_sig; @@ -17742,6 +18185,10 @@ */ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + } AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) { @@ -17771,7 +18218,11 @@ * re-initializing the chip. */ asc_dvc->err_code = 0; - if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + status = AdvInitAsc38C1600Driver(asc_dvc); + } + else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { status = AdvInitAsc38C0800Driver(asc_dvc); } else @@ -17798,6 +18249,10 @@ */ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) + { + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); + } AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) { @@ -17848,6 +18303,7 @@ if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB | ADV_INTR_STATUS_INTRC)) == 0) { + DvcLeaveCritical(flags); return ADV_FALSE; } @@ -17861,13 +18317,18 @@ uchar intrb_code; AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code); - if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && - asc_dvc->carr_pending_cnt != 0) + + if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || + asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && + asc_dvc->carr_pending_cnt != 0) { - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); + if (asc_dvc->chip_type == ADV_CHIP_ASC3550) + { + AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); + } } } @@ -17880,7 +18341,8 @@ /* * Check if the IRQ stopper carrier contains a completed request. */ - while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0) + while (((irq_next_vpa = + le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) { /* * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. @@ -17891,7 +18353,20 @@ * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr' * in AdvExeScsiQueue(). */ - scsiq = (ADV_SCSI_REQ_Q *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->areq_vpa); + scsiq = (ADV_SCSI_REQ_Q *) + ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa)); + + /* + * Request finished with good status and the queue was not + * DMAed to host memory by the firmware. Set all status fields + * to indicate good status. + */ + if ((irq_next_vpa & ASC_RQ_GOOD) != 0) + { + scsiq->done_status = QD_NO_ERROR; + scsiq->host_status = scsiq->scsi_status = 0; + scsiq->data_cnt = 0L; + } /* * Advance the stopper pointer to the next carrier @@ -17902,7 +18377,8 @@ asc_dvc->irq_sp = (ADV_CARR_T *) ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa)); - free_carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist); + free_carrp->next_vpa = + cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); asc_dvc->carr_freelist = free_carrp; asc_dvc->carr_pending_cnt--; @@ -17914,23 +18390,20 @@ */ scsiq->cntl = 0; -#if __BIG_ENDIAN - /* - * After the request completes the only field in the ASC_SCSI_REQ_Q - * structure needs to be byte swapped from little endian order to - * big endian order is the residual data count. - */ - scsiqp->data_cnt = le32_to_cpu(scsiqp->data_cnt); -#endif /* __BIG_ENDIAN */ - /* * If the command that completed was a SCSI INQUIRY and * LUN 0 was sent the command, then process the INQUIRY * command information for the device. + * + * Note: If data returned were either VPD or CmdDt data, + * don't process the INQUIRY command information for + * the device, otherwise may erroneously set *_able bits. */ if (scsiq->done_status == QD_NO_ERROR && scsiq->cdb[0] == SCSICMD_Inquiry && - scsiq->target_lun == 0) + scsiq->target_lun == 0 && + (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT) + == ADV_INQ_RTN_STD_INQUIRY_DATA) { AdvInquiryHandling(asc_dvc, scsiq); } @@ -17982,7 +18455,7 @@ ushort idle_cmd, ADV_DCNT idle_cmd_parameter) { - int last_int_level; + ulong last_int_level; int result; ADV_DCNT i, j; AdvPortAddr iop_base; @@ -18005,8 +18478,8 @@ * followed, the microcode may process the idle command before the * parameters have been written to LRAM. */ - AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER, - idle_cmd_parameter); + AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER, + cpu_to_le32(idle_cmd_parameter)); AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); /* @@ -18072,7 +18545,8 @@ * microcode to the transfer residual count. */ - if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) + if (scsiq->cdb[4] < 8 || + (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) { return; } @@ -18085,7 +18559,7 @@ /* * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices. */ - if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2) + if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) { return; } else @@ -18109,7 +18583,7 @@ * device's 'wdtr_able' bit and write the new value to the * microcode. */ - if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16) + if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) { AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); if ((cfg_word & tidmask) == 0) @@ -18140,7 +18614,7 @@ * supports synchronous transfers, then turn on the device's * 'sdtr_able' bit. Write the new value to the microcode. */ - if ((asc_dvc->sdtr_able & tidmask) && inq->Sync) + if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) { AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); if ((cfg_word & tidmask) == 0) @@ -18158,6 +18632,29 @@ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); } } + /* + * If the Inquiry data included enough space for the SPI-3 + * Clocking field, then check if DT mode is supported. + */ + if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 && + (scsiq->cdb[4] >= 57 || + (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) + { + /* + * PPR (Parallel Protocol Request) Capable + * + * If the device supports DT mode, then it must be PPR capable. + * The PPR message will be used in place of the SDTR and WDTR + * messages to negotiate synchronous speed and offset, transfer + * width, and protocol options. + */ + if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) + { + AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able); + asc_dvc->ppr_able |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able); + } + } /* * If the EEPROM enabled Tag Queuing for the device and the @@ -18171,7 +18668,7 @@ * disabling Tag Queuing in the BIOS devices with Tag Queuing * bugs will at least work with the BIOS. */ - if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue) + if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) { AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); cfg_word |= tidmask; diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h --- v2.4.3/linux/drivers/scsi/advansys.h Mon Dec 11 13:18:51 2000 +++ linux/drivers/scsi/advansys.h Thu Apr 12 12:16:35 2001 @@ -1,9 +1,8 @@ -/* $Id: advansys.h,v 1.18 1999/11/29 21:47:16 bobf Exp bobf $ */ - /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1998 Advanced System Products, Inc. + * Copyright (c) 1995-2000 Advanced System Products, Inc. + * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,49 +10,57 @@ * code retain the above copyright notice and this comment without * modification. * + * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) + * changed its name to ConnectCom Solutions, Inc. + * * There is an AdvanSys Linux WWW page at: + * http://www.connectcom.net/downloads/software/os/linux.html * http://www.advansys.com/linux.html * - * The latest version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux + * The latest released version of the AdvanSys driver is available at: + * ftp://ftp.advansys.com/pub/linux/linux.tgz + * ftp://ftp.connectcom.net/pub/linux/linux.tgz * * Please send questions, comments, bug reports to: - * bobf@advansys.com (Bob Frey) + * linux@connectcom.net or bfrey@turbolinux.com.cn */ #ifndef _ADVANSYS_H #define _ADVANSYS_H -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) - +#include <linux/config.h> #ifndef LINUX_VERSION_CODE #include <linux/version.h> #endif /* LINUX_VERSION_CODE */ +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) +/* Driver supported only in version 2.2 and version >= 2.4. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ + (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ + LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels." +#endif +#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) +#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0)) + /* * Scsi_Host_Template function prototypes. */ int advansys_detect(Scsi_Host_Template *); int advansys_release(struct Scsi_Host *); const char *advansys_info(struct Scsi_Host *); -int advansys_command(Scsi_Cmnd *); int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int advansys_abort(Scsi_Cmnd *); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) int advansys_reset(Scsi_Cmnd *); -#else /* version >= v1.3.89 */ -int advansys_reset(Scsi_Cmnd *, unsigned int); -#endif /* version >= v1.3.89 */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -int advansys_biosparam(Disk *, int, int[]); -#else /* version >= v1.3.0 */ int advansys_biosparam(Disk *, kdev_t, int[]); +#ifdef CONFIG_PROC_FS #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) extern struct proc_dir_entry proc_scsi_advansys; #endif /* version < v2.3.28 */ int advansys_proc_info(char *, char **, off_t, int, int, int); -#endif /* version >= v1.3.0 */ +#else /* !defined(CONFIG_PROC_FS) */ +#define advansys_proc_info NULL +#endif /* !defined(CONFIG_PROC_FS) */ /* init/main.c setup function */ void advansys_setup(char *, int *); @@ -61,108 +68,24 @@ /* * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h. */ -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) -#define ADVANSYS { \ - NULL, /* struct SHT *next */ \ - NULL, /* int *usage_count */ \ - "advansys", /* char *name */ \ - advansys_detect, /* int (*detect)(struct SHT *) */ \ - advansys_release, /* int (*release)(struct Scsi_Host *) */ \ - advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ - advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ - advansys_queuecommand, \ - /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ - advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ - advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ - NULL, /* int (*slave_attach)(int, int) */ \ - advansys_biosparam, /* int (* bios_param)(Disk *, int, int []) */ \ - /* \ - * The following fields are set per adapter in advansys_detect(). \ - */ \ - 0, /* int can_queue */ \ - 0, /* int this_id */ \ - 0, /* short unsigned int sg_tablesize */ \ - 0, /* short cmd_per_lun */ \ - 0, /* unsigned char present */ \ - /* \ - * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ - * must be set. The flag will be cleared in advansys_detect for non-ISA \ - * adapters. Refer to the comment in scsi_module.c for more information. \ - */ \ - 1, /* unsigned unchecked_isa_dma:1 */ \ - /* \ - * All adapters controlled by this driver are capable of large \ - * scatter-gather lists. According to the mid-level SCSI documentation \ - * this obviates any performance gain provided by setting \ - * 'use_clustering'. But empirically while CPU utilization is increased \ - * by enabling clustering, I/O throughput increases as well. \ - */ \ - ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ -} -#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) -#define ADVANSYS { \ - NULL, /* struct SHT *next */ \ - NULL, \ - /* version < v2.1.23 long *usage_count */ \ - /* version >= v2.1.23 struct module * */ \ - &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \ - advansys_proc_info, \ - /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \ - "advansys", /* const char *name */ \ - advansys_detect, /* int (*detect)(struct SHT *) */ \ - advansys_release, /* int (*release)(struct Scsi_Host *) */ \ - advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ - advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ - advansys_queuecommand, \ - /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ - advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ - advansys_reset, \ - /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \ - /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \ - NULL, /* int (*slave_attach)(int, int) */ \ - advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \ - /* \ - * The following fields are set per adapter in advansys_detect(). \ - */ \ - 0, /* int can_queue */ \ - 0, /* int this_id */ \ - 0, /* short unsigned int sg_tablesize */ \ - 0, /* short cmd_per_lun */ \ - 0, /* unsigned char present */ \ - /* \ - * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ - * must be set. The flag will be cleared in advansys_detect for non-ISA \ - * adapters. Refer to the comment in scsi_module.c for more information. \ - */ \ - 1, /* unsigned unchecked_isa_dma:1 */ \ - /* \ - * All adapters controlled by this driver are capable of large \ - * scatter-gather lists. According to the mid-level SCSI documentation \ - * this obviates any performance gain provided by setting \ - * 'use_clustering'. But empirically while CPU utilization is increased \ - * by enabling clustering, I/O throughput increases as well. \ - */ \ - ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ -} -#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) +#if ASC_LINUX_KERNEL24 #define ADVANSYS { \ - proc_dir: &proc_scsi_advansys, \ - proc_info: advansys_proc_info, \ - name: "advansys", \ - detect: advansys_detect, \ - release: advansys_release, \ - info: advansys_info, \ - command: advansys_command, \ - queuecommand: advansys_queuecommand, \ - abort: advansys_abort, \ - reset: advansys_reset, \ - bios_param: advansys_biosparam, \ + proc_name: "advansys", \ + proc_info: advansys_proc_info, \ + name: "advansys", \ + detect: advansys_detect, \ + release: advansys_release, \ + info: advansys_info, \ + queuecommand: advansys_queuecommand, \ + use_new_eh_code: 1, \ + eh_bus_reset_handler: advansys_reset, \ + bios_param: advansys_biosparam, \ /* \ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ * must be set. The flag will be cleared in advansys_detect for non-ISA \ * adapters. Refer to the comment in scsi_module.c for more information. \ */ \ - unchecked_isa_dma: 1, \ + unchecked_isa_dma: 1, \ /* \ * All adapters controlled by this driver are capable of large \ * scatter-gather lists. According to the mid-level SCSI documentation \ @@ -170,27 +93,25 @@ * 'use_clustering'. But empirically while CPU utilization is increased \ * by enabling clustering, I/O throughput increases as well. \ */ \ - use_clustering: ENABLE_CLUSTERING, \ + use_clustering: ENABLE_CLUSTERING, \ } -#else /* version >= v2.3.28 */ +#elif ASC_LINUX_KERNEL22 #define ADVANSYS { \ - proc_name: "advansys", \ - proc_info: advansys_proc_info, \ - name: "advansys", \ - detect: advansys_detect, \ - release: advansys_release, \ - info: advansys_info, \ - command: advansys_command, \ - queuecommand: advansys_queuecommand, \ - abort: advansys_abort, \ - reset: advansys_reset, \ - bios_param: advansys_biosparam, \ + proc_info: advansys_proc_info, \ + name: "advansys", \ + detect: advansys_detect, \ + release: advansys_release, \ + info: advansys_info, \ + queuecommand: advansys_queuecommand, \ + use_new_eh_code: 1, \ + eh_bus_reset_handler: advansys_reset, \ + bios_param: advansys_biosparam, \ /* \ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ * must be set. The flag will be cleared in advansys_detect for non-ISA \ * adapters. Refer to the comment in scsi_module.c for more information. \ */ \ - unchecked_isa_dma: 1, \ + unchecked_isa_dma: 1, \ /* \ * All adapters controlled by this driver are capable of large \ * scatter-gather lists. According to the mid-level SCSI documentation \ @@ -198,7 +119,7 @@ * 'use_clustering'. But empirically while CPU utilization is increased \ * by enabling clustering, I/O throughput increases as well. \ */ \ - use_clustering: ENABLE_CLUSTERING, \ + use_clustering: ENABLE_CLUSTERING, \ } -#endif /* version >= v2.3.28 */ +#endif #endif /* _ADVANSYS_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c --- v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Thu Apr 12 12:16:35 2001 @@ -112,6 +112,7 @@ * 8: SMP friendliness has been improved * */ +#include <linux/config.h> /* * The next three defines are user configurable. These should be the only diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h --- v2.4.3/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Tue Mar 6 22:44:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Thu Apr 12 12:16:35 2001 @@ -355,10 +355,6 @@ #define AIC7XXX_DRIVER_VERSION "6.1.5" -#ifndef LINUX_VERSION_CODE -#include <linux/version.h> -#endif - #ifndef KERNEL_VERSION #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) #endif diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg linux/drivers/scsi/aic7xxx_old/aic7xxx.reg --- v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.reg Fri Apr 6 10:51:19 2001 @@ -14,7 +14,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq linux/drivers/scsi/aic7xxx_old/aic7xxx.seq --- v2.4.3/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.seq Fri Apr 6 10:51:19 2001 @@ -14,7 +14,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License (GPL) and the terms of the GPL would require the + * the GNU General Public License (GPL) and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old/sequencer.h linux/drivers/scsi/aic7xxx_old/sequencer.h --- v2.4.3/linux/drivers/scsi/aic7xxx_old/sequencer.h Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old/sequencer.h Fri Apr 6 10:51:19 2001 @@ -15,7 +15,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c --- v2.4.3/linux/drivers/scsi/aic7xxx_old.c Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old.c Fri Apr 6 10:51:19 2001 @@ -55,7 +55,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c --- v2.4.3/linux/drivers/scsi/fastlane.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/fastlane.c Wed Apr 11 19:02:37 2001 @@ -76,7 +76,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ @@ -96,9 +96,7 @@ * this ID value. Fortunately only Fastlane maps in Z3 space */ if (board < 0x1000000) { - release_mem_region(board+FASTLANE_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; + goto err_release; } esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR); @@ -146,10 +144,7 @@ if(!address){ printk("Could not remap Fastlane controller memory!"); - scsi_unregister (esp->ehost); - release_mem_region(board+FASTLANE_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; + goto err_unregister; } @@ -171,8 +166,11 @@ esp->irq = IRQ_AMIGA_PORTS; esp->slot = board+FASTLANE_ESP_ADDR; - request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, - "Fastlane SCSI", esp_intr); + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, + "Fastlane SCSI", esp_intr)) { + printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS); + goto err_unmap; + } /* Controller ID */ esp->scsi_id = 7; @@ -188,6 +186,15 @@ return esps_in_use; } } + return 0; + + err_unmap: + iounmap((void *)address); + err_unregister: + scsi_unregister (esp->ehost); + err_release: + release_mem_region(z->resource.start+FASTLANE_ESP_ADDR, + sizeof(struct ESP_regs)); return 0; } diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.4.3/linux/drivers/scsi/megaraid.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/scsi/megaraid.c Fri Apr 13 20:26:07 2001 @@ -75,7 +75,7 @@ * Changed megaraid_command to use wait_queue. * * Version 1.00: - * Checks to see if an irq ocurred while in isr, and runs through + * Checks to see if an irq occurred while in isr, and runs through * routine again. * Copies mailbox to temp area before processing in isr * Added barrier() in busy wait to fix volatility bug @@ -293,6 +293,9 @@ * Left 2.0 support but removed 2.1.x support. * Collected much of the compat glue into one spot * + * Version 1.14g-ac2 - 22/03/01 + * Fixed a non obvious dereference after free in the driver unload path + * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that * fails to detect the controller as a pci device on the system. @@ -391,6 +394,11 @@ writel (value, megaCfg->base + 0x2C); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */ +#include <linux/smp.h> +#define cpuid smp_processor_id() +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */ /* @@ -401,9 +409,6 @@ * queue task is a simple api without irq forms */ -#include <linux/smp.h> -#define cpuid smp_processor_id() - MODULE_AUTHOR ("American Megatrends Inc."); MODULE_DESCRIPTION ("AMI MegaRAID driver"); @@ -428,10 +433,8 @@ * No pci region api * queue_task is now a single simple API */ - -#include <linux/smp.h> -#define cpuid smp_processor_id() +static char kernel_version[] = UTS_RELEASE; MODULE_AUTHOR ("American Megatrends Inc."); MODULE_DESCRIPTION ("AMI MegaRAID driver"); @@ -2764,7 +2767,6 @@ sizeof (mega_mailbox64), (void *) megaCfg->mailbox64ptr, megaCfg->dma_handle64); - scsi_unregister (pSHost); #ifdef CONFIG_PROC_FS if (megaCfg->controller_proc_dir_entry) { @@ -2785,12 +2787,21 @@ #endif /* + * Release the controller memory. A word of warning this frees + * hostdata and that includes megaCfg-> so be careful what you + * dereference beyond this point + */ + + scsi_unregister (pSHost); + + /* * Unregister the character device interface to the driver. Ideally this * should have been done in cleanup_module routine. Since this is hidden * in file "scsi_module.c", we do it here. * major is the major number of the character device returned by call to * register_chrdev() routine. */ + unregister_chrdev (major, "megadev"); unregister_reboot_notifier (&mega_notifier); @@ -4299,12 +4310,10 @@ } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -static Scsi_Host_Template driver_template = MEGARAID; -#include "scsi_module.c" -#else -#ifdef MODULE +static +#endif /* LINUX VERSION 2.4.XX */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE) Scsi_Host_Template driver_template = MEGARAID; #include "scsi_module.c" -#endif /* MODULE */ -#endif /* LINUX VERSION 2.4.XX test */ +#endif /* LINUX VERSION 2.4.XX || MODULE */ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h --- v2.4.3/linux/drivers/scsi/megaraid.h Tue Mar 6 19:44:37 2001 +++ linux/drivers/scsi/megaraid.h Fri Apr 13 20:26:07 2001 @@ -27,7 +27,7 @@ #define M_RD_IOCTL_CMD_NEW 0x81 #define M_RD_DRIVER_IOCTL_INTERFACE 0x82 -#define MEGARAID_VERSION "v1.14g (Release Date: Feb 5, 2001; 11:42)" +#define MEGARAID_VERSION "v1.14g-ac2 (Release Date: Mar 22, 2001; 19:34:02)" #define MEGARAID_IOCTL_VERSION 114 /* Methods */ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.4.3/linux/drivers/scsi/ncr53c8xx.c Tue Mar 6 19:34:25 2001 +++ linux/drivers/scsi/ncr53c8xx.c Thu Apr 12 12:16:35 2001 @@ -9271,9 +9271,9 @@ */ #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) -static Scsi_Host_Template driver_template = NCR53C8XX; -#include "scsi_module.c" -#elif defined(MODULE) +static +#endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE) Scsi_Host_Template driver_template = NCR53C8XX; #include "scsi_module.c" #endif diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c --- v2.4.3/linux/drivers/scsi/qlogicfas.c Mon Sep 18 13:36:25 2000 +++ linux/drivers/scsi/qlogicfas.c Wed Apr 11 19:02:37 2001 @@ -23,7 +23,7 @@ Functions as standalone, loadable, and PCMCIA driver, the latter from Dave Hinds' PCMCIA package. - Redistributable under terms of the GNU Public License + Redistributable under terms of the GNU General Public License */ /*----------------------------------------------------------------*/ @@ -118,6 +118,7 @@ #include <linux/blk.h> /* to get disk capacity */ #include <linux/kernel.h> #include <linux/string.h> +#include <linux/init.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/proc_fs.h> @@ -128,11 +129,11 @@ #include "sd.h" #include "hosts.h" #include "qlogicfas.h" -#include<linux/stat.h> +#include <linux/stat.h> /*----------------------------------------------------------------*/ /* driver state info, local to driver */ -static int qbase = 0; /* Port */ +static int qbase; /* Port */ static int qinitid; /* initiator ID */ static int qabort; /* Flag to cause an abort */ static int qlirq = -1; /* IRQ being used */ @@ -537,7 +538,7 @@ /*----------------------------------------------------------------*/ /* look for qlogic card and init if found */ -int qlogicfas_detect(Scsi_Host_Template * host) +int __QLINIT qlogicfas_detect(Scsi_Host_Template * host) { int i, j; /* these are only used by IRQ detect */ int qltyp; /* type of chip */ @@ -556,7 +557,7 @@ if( !qbase ) { for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { - if( check_region( qbase , 0x10 ) ) + if( !request_region( qbase , 0x10, "qlogicfas" ) ) continue; REG1; if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) @@ -616,8 +617,9 @@ if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL)) host->can_queue = 1; #endif - request_region( qbase , 0x10 ,"qlogicfas"); hreg = scsi_register( host , 0 ); /* no host data */ + if (!hreg) + goto err_release_mem; hreg->io_port = qbase; hreg->n_io_port = 16; hreg->dma_channel = -1; @@ -629,6 +631,13 @@ host->name = qinfo; return 1; + + err_release_mem: + release_region(qbase, 0x10); + if (host->can_queue) + free_irq(qlirq, do_ql_ihandl); + return 0; + } /*----------------------------------------------------------------*/ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/qlogicfas.h linux/drivers/scsi/qlogicfas.h --- v2.4.3/linux/drivers/scsi/qlogicfas.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/qlogicfas.h Wed Apr 11 19:02:37 2001 @@ -13,6 +13,12 @@ #define NULL (0) #endif +#ifdef PCMCIA +#define __QLINIT __devinit +#else +#define __QLINIT __init +#endif + #define QLOGICFAS { \ detect: qlogicfas_detect, \ info: qlogicfas_info, \ diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.4.3/linux/drivers/scsi/qlogicfc.c Tue Mar 20 15:05:46 2001 +++ linux/drivers/scsi/qlogicfc.c Fri Apr 13 20:26:07 2001 @@ -195,8 +195,8 @@ #define FLASH_BIOS_ADDR 0x00 #define FLASH_BIOS_DATA 0x02 #define ISP_CTRL_STATUS 0x06 /* configuration register #1 */ -#define PCI_INTER_CTL 0x08 /* pci interupt control */ -#define PCI_INTER_STS 0x0a /* pci interupt status */ +#define PCI_INTER_CTL 0x08 /* pci interrupt control */ +#define PCI_INTER_STS 0x0a /* pci interrupt status */ #define PCI_SEMAPHORE 0x0c /* pci semaphore */ #define PCI_NVRAM 0x0e /* pci nvram interface */ @@ -227,7 +227,7 @@ #define REQUEST_TRANSFER_ERROR 0x8003 #define RESPONSE_TRANSFER_ERROR 0x8004 #define REQUEST_QUEUE_WAKEUP 0x8005 -#define LIP_OCCURED 0x8010 +#define LIP_OCCURRED 0x8010 #define LOOP_UP 0x8011 #define LOOP_DOWN 0x8012 #define LIP_RECEIVED 0x8013 @@ -369,7 +369,7 @@ #define STF_ABORTED 0x0020 #define STF_TIMEOUT 0x0040 -/* interupt control commands */ +/* interrupt control commands */ #define ISP_EN_INT 0x8000 #define ISP_EN_RISC 0x0008 @@ -757,6 +757,10 @@ continue; host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); + if (!host) { + printk("qlogicfc%d : could not register host.\n", hostdata->host_id); + continue; + } host->max_id = QLOGICFC_MAX_ID + 1; host->max_lun = QLOGICFC_MAX_LUN; host->hostt->use_new_eh_code = 1; @@ -768,6 +772,7 @@ if (!hostdata->res){ printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id); + pci64_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -813,7 +818,7 @@ scsi_unregister(host); continue; } - if (check_region(host->io_port, 0xff)) { + if (!request_region(host->io_port, 0xff, "qlogicfc")) { printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); @@ -822,7 +827,6 @@ scsi_unregister(host); continue; } - request_region(host->io_port, 0xff, "qlogicfc"); outw(0x0, host->io_port + PCI_SEMAPHORE); outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); @@ -1520,7 +1524,7 @@ if (hostdata->adapter_state == AS_LOOP_GOOD) hostdata->adapter_state = AS_REDO_FABRIC_PORTDB; break; - case LIP_OCCURED: + case LIP_OCCURRED: case LIP_RECEIVED: printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id); if (hostdata->adapter_state == AS_LOOP_GOOD) @@ -1866,7 +1870,9 @@ hostdata = (struct isp2x00_hostdata *) host->hostdata; outw(0x01, host->io_port + ISP_CTRL_STATUS); + udelay(100); outw(HCCR_RESET, host->io_port + HOST_HCCR); + udelay(100); outw(HCCR_RELEASE, host->io_port + HOST_HCCR); outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.4.3/linux/drivers/scsi/scsi_scan.c Sun Feb 4 10:05:30 2001 +++ linux/drivers/scsi/scsi_scan.c Sun Apr 8 10:10:01 2001 @@ -139,6 +139,7 @@ {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, {"TOSHIBA","CDROM","*", BLIST_ISROM}, + {"TOSHIBA","CD-ROM","*", BLIST_ISROM}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, {"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0) {"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.4.3/linux/drivers/scsi/sym53c8xx.c Tue Mar 20 12:04:58 2001 +++ linux/drivers/scsi/sym53c8xx.c Thu Apr 12 12:16:35 2001 @@ -14672,9 +14672,9 @@ */ #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) -static Scsi_Host_Template driver_template = SYM53C8XX; -#include "scsi_module.c" -#elif defined(MODULE) +static +#endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE) Scsi_Host_Template driver_template = SYM53C8XX; #include "scsi_module.c" #endif diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.4.3/linux/drivers/scsi/tmscsim.c Fri Feb 16 16:06:17 2001 +++ linux/drivers/scsi/tmscsim.c Wed Apr 11 19:02:37 2001 @@ -206,10 +206,7 @@ #define DCBDEBUG1(x) /* Includes */ -#ifdef MODULE -# include <linux/module.h> -#endif - +#include <linux/module.h> #include <asm/dma.h> #include <asm/io.h> #include <asm/system.h> @@ -663,16 +660,30 @@ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) -void __init dc390_setup (char *str) +int __init dc390_setup (char *str) { int ints[8]; int i, im; (void)get_options (str, ARRAY_SIZE(ints), ints); + im = ints[0]; + if (im > 6) + { + printk (KERN_NOTICE "DC390: ignore extra params!\n"); + im = 6; + }; + for (i = 0; i < im; i++) + tmscsim[i] = ints[i+1]; + /* dc390_checkparams (); */ + return 1; +}; +#ifndef MODULE +__setup("tmscsim=", dc390_setup); +#endif + #else void __init dc390_setup (char *str, int *ints) { int i, im; -#endif im = ints[0]; if (im > 6) { @@ -683,14 +694,10 @@ tmscsim[i] = ints[i+1]; /* dc390_checkparams (); */ }; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) -#ifndef MODULE -__setup("tmscsim=", dc390_setup); -#endif #endif + static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) { UCHAR bval; @@ -828,7 +835,7 @@ /* Queueing philosphy: * There are a couple of lists: * - Query: Contains the Scsi Commands not yet turned into SRBs (per ACB) - * (Note: For new EH, it is unecessary!) + * (Note: For new EH, it is unnecessary!) * - Waiting: Contains a list of SRBs not yet sent (per DCB) * - Free: List of free SRB slots * @@ -2852,7 +2859,7 @@ { int dev, spd, spd1; char *pos = buffer; - PSH shpnt; + PSH shpnt = 0; PACB pACB; PDCB pDCB; PSCSICMD pcmd; diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h --- v2.4.3/linux/drivers/scsi/tmscsim.h Sun Dec 31 11:06:00 2000 +++ linux/drivers/scsi/tmscsim.h Wed Apr 11 19:02:37 2001 @@ -10,15 +10,6 @@ #include <linux/types.h> #include <linux/config.h> -/* 2.0 compat */ -#if defined(__SMP__) && !defined(CONFIG_SMP) -# if LINUX_VERSION_CODE < KERNEL_VERSION (2,2,0) -# define CONFIG_SMP -# else -# error __SMP__ defined but not CONFIG_SMP -# endif -#endif - #define IRQ_NONE 255 diff -u --recursive --new-file v2.4.3/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.4.3/linux/drivers/scsi/wd7000.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/wd7000.c Wed Apr 11 19:02:37 2001 @@ -863,7 +863,7 @@ */ if (freescbs < needed) { busy = 0; - panic ("wd7000: can't get enough free SCBs.\n"); + printk (KERN_ERR "wd7000: can't get enough free SCBs.\n"); restore_flags (flags); return (NULL); } @@ -1593,7 +1593,7 @@ printk ("wd7000_detect: check IO 0x%x region...\n", iobase); #endif - if (!check_region (iobase, 4)) { + if (request_region (iobase, 4, "wd7000")) { #ifdef WD7000_DEBUG printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); @@ -1609,12 +1609,12 @@ #ifdef WD7000_DEBUG { printk ("failed!\n"); - continue; + goto err_release; } - else + else printk ("ok!\n"); #else - continue; + goto err_release; #endif if (inb (iobase + ASC_INTR_STAT) == 1) { @@ -1627,7 +1627,8 @@ */ sh = scsi_register (tpnt, sizeof (Adapter)); if(sh==NULL) - continue; + goto err_release; + host = (Adapter *) sh->hostdata; #ifdef WD7000_DEBUG @@ -1650,11 +1651,8 @@ host->iobase, host->irq, host->dma); #endif - if (!wd7000_init (host)) { /* Initialization failed */ - scsi_unregister (sh); - - continue; - } + if (!wd7000_init (host)) /* Initialization failed */ + goto err_unregister; /* * OK from here - we'll use this adapter/configuration. @@ -1662,11 +1660,6 @@ wd7000_revision (host); /* important for scatter/gather */ /* - * Register our ports. - */ - request_region (host->iobase, 4, "wd7000"); - - /* * For boards before rev 6.0, scatter/gather isn't supported. */ if (host->rev1 < 6) @@ -1690,6 +1683,13 @@ else printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase); #endif + + continue; + + err_unregister: + scsi_unregister (sh); + err_release: + release_region(iobase, 4); } diff -u --recursive --new-file v2.4.3/linux/drivers/sgi/Makefile linux/drivers/sgi/Makefile --- v2.4.3/linux/drivers/sgi/Makefile Sun Aug 6 11:23:40 2000 +++ linux/drivers/sgi/Makefile Fri Apr 13 20:26:07 2001 @@ -7,17 +7,13 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) char -ALL_SUB_DIRS := $(SUB_DIRS) char - - -L_OBJS := L_TARGET := sgi.a +# # Character and Audio devices for SGI machines. # -SUB_DIRS += char -L_OBJS += char/sgichar.o +subdir-y += char +subdir-m += char +obj-y += char/sgichar.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/drivers/sgi/char/Makefile linux/drivers/sgi/char/Makefile --- v2.4.3/linux/drivers/sgi/char/Makefile Fri Jun 25 17:39:34 1999 +++ linux/drivers/sgi/char/Makefile Fri Apr 13 20:26:07 2001 @@ -8,25 +8,12 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := sgichar.o -OX_OBJS := newport.o -O_OBJS := sgicons.o \ - usema.o shmiq.o streamable.o -ifeq ($(CONFIG_SGI_SERIAL),y) - O_OBJS += sgiserial.o -endif +export-objs := newport.o shmiq.o sgicons.o usema.o +obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o -ifeq ($(CONFIG_SGI_DS1286),y) - O_OBJS += ds1286.o -endif - -ifeq ($(CONFIG_SGI_NEWPORT_GFX),y) - O_OBJS += graphics.o rrm.o -else -ifeq ($(CONFIG_SGI_NEWPORT_GFX),m) - OX_OBJS += graphics_syms.o - MX_OBJS += graphics.o rrm.o -endif -endif +obj-$(CONFIG_SGI_SERIAL) += sgiserial.o +obj-$(CONFIG_SGI_DS1286) += ds1286.o +obj-$(CONFIG_SGI_NEWPORT_GFX) += graphics.o rrm.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.4.3/linux/drivers/sound/Config.in Tue Mar 6 19:28:32 2001 +++ linux/drivers/sound/Config.in Fri Apr 13 20:26:07 2001 @@ -93,7 +93,7 @@ fi dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS dep_tristate ' Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS - dep_tristate ' ACI mixer (miroPCM12)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS + dep_tristate ' ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS dep_tristate ' Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS dep_tristate ' Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS dep_tristate ' Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS @@ -171,8 +171,10 @@ fi if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS - dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then + dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS + fi + dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER fi fi diff -u --recursive --new-file v2.4.3/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.4.3/linux/drivers/sound/Makefile Sun Feb 4 10:05:29 2001 +++ linux/drivers/sound/Makefile Fri Apr 13 20:26:07 2001 @@ -10,7 +10,7 @@ export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \ msnd.o opl3.o sb_common.o sequencer_syms.o \ sound_core.o sound_syms.o uart401.o \ - nm256_audio.o ac97.o ac97_codec.o + nm256_audio.o ac97.o ac97_codec.o aci.o # Each configuration option enables a list of files. @@ -29,7 +29,7 @@ obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o -obj-$(CONFIG_SOUND_PAS) += pas2.o sb_lib.o uart401.o +obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.4.3/linux/drivers/sound/ac97_codec.c Thu Dec 7 00:21:37 2000 +++ linux/drivers/sound/ac97_codec.c Fri Apr 6 10:51:19 2001 @@ -20,6 +20,16 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ************************************************************************** + * + * The Intel Audio Codec '97 specification is available at the Intel + * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/ + * + * The specification itself is currently available at: + * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf + * + ************************************************************************** + * * History * v0.4 Mar 15 2000 Ollie Lho * dual codecs support verified with 4 channels output @@ -49,41 +59,61 @@ static int ac97_init_mixer(struct ac97_codec *codec); -static int sigmatel_init(struct ac97_codec *codec); +static int wolfson_init(struct ac97_codec * codec); +static int tritech_init(struct ac97_codec * codec); +static int tritech_maestro_init(struct ac97_codec * codec); +static int sigmatel_9708_init(struct ac97_codec *codec); +static int sigmatel_9721_init(struct ac97_codec *codec); +static int sigmatel_9744_init(struct ac97_codec *codec); static int enable_eapd(struct ac97_codec *codec); -#define arraysize(x) (sizeof(x)/sizeof((x)[0])) - -static struct { - unsigned int id; +/* sorted by vendor/device id */ +static const struct { + u32 id; char *name; int (*init) (struct ac97_codec *codec); } ac97_codec_ids[] = { - {0x414B4D00, "Asahi Kasei AK4540 rev 0", NULL}, - {0x414B4D01, "Asahi Kasei AK4540 rev 1", NULL}, - {0x41445340, "Analog Devices AD1881" , NULL}, - {0x41445360, "Analog Devices AD1885" , enable_eapd}, - {0x43525900, "Cirrus Logic CS4297" , NULL}, - {0x43525903, "Cirrus Logic CS4297" , NULL}, - {0x43525913, "Cirrus Logic CS4297A" , NULL}, - {0x43525923, "Cirrus Logic CS4298" , NULL}, - {0x4352592B, "Cirrus Logic CS4294" , NULL}, - {0x43525931, "Cirrus Logic CS4299" , NULL}, - {0x43525934, "Cirrus Logic CS4299" , NULL}, - {0x4e534331, "National Semiconductor LM4549" , NULL}, - {0x53494c22, "Silicon Laboratory Si3036" , NULL}, - {0x53494c23, "Silicon Laboratory Si3038" , NULL}, - {0x83847600, "SigmaTel STAC????" , NULL}, + {0x41445303, "Analog Devices AD1819", NULL}, + {0x41445340, "Analog Devices AD1881", NULL}, + {0x41445348, "Analog Devices AD1881A", NULL}, + {0x41445460, "Analog Devices AD1885", enable_eapd}, + {0x414B4D00, "Asahi Kasei AK4540", NULL}, + {0x414B4D01, "Asahi Kasei AK4542", NULL}, + {0x414B4D02, "Asahi Kasei AK4543", NULL}, + {0x414C4710, "ALC200/200P", NULL}, + {0x43525900, "Cirrus Logic CS4297", enable_eapd}, + {0x43525903, "Cirrus Logic CS4297", enable_eapd}, + {0x43525913, "Cirrus Logic CS4297A rev A", enable_eapd}, + {0x43525914, "Cirrus Logic CS4297A rev B", NULL}, + {0x43525923, "Cirrus Logic CS4298", NULL}, + {0x4352592B, "Cirrus Logic CS4294", NULL}, + {0x4352592D, "Cirrus Logic CS4294", NULL}, + {0x43525931, "Cirrus Logic CS4299 rev A", NULL}, + {0x43525933, "Cirrus Logic CS4299 rev C", NULL}, + {0x43525934, "Cirrus Logic CS4299 rev D", NULL}, + {0x45838308, "ESS Allegro ES1988", NULL}, + {0x49434511, "ICE1232", NULL}, /* I hope --jk */ + {0x4e534331, "National Semiconductor LM4549", NULL}, + {0x53494c22, "Silicon Laboratory Si3036", NULL}, + {0x53494c23, "Silicon Laboratory Si3038", NULL}, + {0x545200FF, "TriTech TR?????", tritech_maestro_init}, + {0x54524102, "TriTech TR28022", NULL}, + {0x54524103, "TriTech TR28023", NULL}, + {0x54524106, "TriTech TR28026", NULL}, + {0x54524108, "TriTech TR28028", tritech_init}, + {0x54524123, "TriTech TR?????", NULL}, + {0x574D4C00, "Wolfson WM9704", wolfson_init}, + {0x574D4C03, "Wolfson WM9703/9704", wolfson_init}, + {0x574D4C04, "Wolfson WM9704 (quad)", wolfson_init}, + {0x83847600, "SigmaTel STAC????", NULL}, {0x83847604, "SigmaTel STAC9701/3/4/5", NULL}, - {0x83847605, "SigmaTel STAC9704" , NULL}, - {0x83847608, "SigmaTel STAC9708" , NULL}, - {0x83847609, "SigmaTel STAC9721/23" , sigmatel_init}, - {0x54524103, "TriTech TR?????" , NULL}, - {0x54524106, "TriTech TR28026" , NULL}, - {0x54524108, "TriTech TR28028" , NULL}, - {0x54524123, "TriTech TR?????" , NULL}, - {0x574D4C00, "Wolfson WM9704" , NULL}, - {0x00000000, NULL, NULL} + {0x83847605, "SigmaTel STAC9704", NULL}, + {0x83847608, "SigmaTel STAC9708", sigmatel_9708_init}, + {0x83847609, "SigmaTel STAC9721/23", sigmatel_9721_init}, + {0x83847644, "SigmaTel STAC9744/45", sigmatel_9744_init}, + {0x83847656, "SigmaTel STAC9756/57", sigmatel_9744_init}, + {0x83847684, "SigmaTel STAC9783/84?", NULL}, + {0,} }; static const char *ac97_stereo_enhancements[] = @@ -175,10 +205,10 @@ AC97_REC_LINE, AC97_REC_STEREO, /* combination of all enabled outputs.. */ AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE + AC97_REC_PHONE }; -static unsigned int ac97_rm2oss[] = { +static const unsigned int ac97_rm2oss[] = { [AC97_REC_MIC] = SOUND_MIXER_MIC, [AC97_REC_CD] = SOUND_MIXER_CD, [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, @@ -189,7 +219,7 @@ }; /* indexed by bit position */ -static unsigned int ac97_oss_rm[] = { +static const unsigned int ac97_oss_rm[] = { [SOUND_MIXER_MIC] = AC97_REC_MIC, [SOUND_MIXER_CD] = AC97_REC_CD, [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, @@ -431,13 +461,13 @@ return 0; } - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) return -EINVAL; if (cmd == OSS_GETVERSION) return put_user(SOUND_VERSION, (int *)arg); - if (_IOC_DIR(cmd) == _IOC_READ) { + if (_SIOC_DIR(cmd) == _SIOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* give them the current record source */ if (!codec->recmask_io) { @@ -477,7 +507,7 @@ return put_user(val, (int *)arg); } - if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { + if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) { codec->modcnt++; if (get_user(val, (int *)arg)) return -EFAULT; @@ -640,7 +670,7 @@ id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - for (i = 0; i < arraysize(ac97_codec_ids); i++) { + for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { codec->type = ac97_codec_ids[i].id; codec->name = ac97_codec_ids[i].name; @@ -691,7 +721,7 @@ codec->codec_init(codec); } - /* initilize mixer channel volumes */ + /* initialize mixer channel volumes */ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { struct mixer_defaults *md = &mixer_defaults[i]; if (md->mixer == -1) @@ -704,40 +734,151 @@ return 1; } -static int sigmatel_init(struct ac97_codec * codec) +#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */ +#define AC97_SIGMATEL_DAC2INVERT 0x6e +#define AC97_SIGMATEL_BIAS1 0x70 +#define AC97_SIGMATEL_BIAS2 0x72 +#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */ +#define AC97_SIGMATEL_CIC1 0x76 +#define AC97_SIGMATEL_CIC2 0x78 + + +static int sigmatel_9708_init(struct ac97_codec * codec) +{ + u16 codec72, codec6c; + + codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000; + codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG); + + if ((codec72==0) && (codec6c==0)) { + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000); + codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007); + } else if ((codec72==0x8000) && (codec6c==0)) { + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001); + codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008); + } else if ((codec72==0x8000) && (codec6c==0x0080)) { + /* nothing */ + } + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); + return 0; +} + + +static int sigmatel_9721_init(struct ac97_codec * codec) { /* Only set up secondary codec */ if (codec->id == 0) - return 1; + return 0; codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link sloc 3,4 = 0x01, slot 7,8 = 0x00, */ - codec->codec_write(codec, 0x74, 0x00); + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00); /* we don't have the crystal when we are on an AMR card, so use BIT_CLK as our clock source. Write the magic word ABBA and read back to enable register 0x78 */ - codec->codec_write(codec, 0x76, 0xabba); - codec->codec_read(codec, 0x76); + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_read(codec, AC97_SIGMATEL_CIC1); /* sync all the clocks*/ - codec->codec_write(codec, 0x78, 0x3802); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802); - return 1; + return 0; +} + + +static int sigmatel_9744_init(struct ac97_codec * codec) +{ + // patch for SigmaTel + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk + codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002); + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); + return 0; +} + + +static int wolfson_init(struct ac97_codec * codec) +{ + codec->codec_write(codec, 0x72, 0x0808); + codec->codec_write(codec, 0x74, 0x0808); + + // patch for DVD noise + codec->codec_write(codec, 0x5a, 0x0200); + + // init vol as PCM vol + codec->codec_write(codec, 0x70, + codec->codec_read(codec, AC97_PCMOUT_VOL)); + + codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); + return 0; +} + + +static int tritech_init(struct ac97_codec * codec) +{ + codec->codec_write(codec, 0x26, 0x0300); + codec->codec_write(codec, 0x26, 0x0000); + codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); + codec->codec_write(codec, AC97_RESERVED_3A, 0x0000); + return 0; +} + + +/* copied from drivers/sound/maestro.c */ +static int tritech_maestro_init(struct ac97_codec * codec) +{ + /* no idea what this does */ + codec->codec_write(codec, 0x2A, 0x0001); + codec->codec_write(codec, 0x2C, 0x0000); + codec->codec_write(codec, 0x2C, 0XFFFF); + return 0; } + /* - * Bring up an AD1885 + * External AMP management for EAPD using codecs + * (CS4279A, AD1885, ...) */ - + static int enable_eapd(struct ac97_codec * codec) { codec->codec_write(codec, AC97_POWER_CONTROL, codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); return 0; } + + +/* copied from drivers/sound/maestro.c */ +#if 0 /* there has been 1 person on the planet with a pt101 that we + know of. If they care, they can put this back in :) */ +static int pt101_init(struct ac97_codec * codec) +{ + printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); + /* who knows.. */ + codec->codec_write(codec, 0x2A, 0x0001); + codec->codec_write(codec, 0x2C, 0x0000); + codec->codec_write(codec, 0x2C, 0xFFFF); + codec->codec_write(codec, 0x10, 0x9F1F); + codec->codec_write(codec, 0x12, 0x0808); + codec->codec_write(codec, 0x14, 0x9F1F); + codec->codec_write(codec, 0x16, 0x9F1F); + codec->codec_write(codec, 0x18, 0x0404); + codec->codec_write(codec, 0x1A, 0x0000); + codec->codec_write(codec, 0x1C, 0x0000); + codec->codec_write(codec, 0x02, 0x0404); + codec->codec_write(codec, 0x04, 0x0808); + codec->codec_write(codec, 0x0C, 0x801F); + codec->codec_write(codec, 0x0E, 0x801F); + return 0; +} +#endif EXPORT_SYMBOL(ac97_read_proc); diff -u --recursive --new-file v2.4.3/linux/drivers/sound/aci.c linux/drivers/sound/aci.c --- v2.4.3/linux/drivers/sound/aci.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/sound/aci.c Fri Apr 13 20:26:07 2001 @@ -10,15 +10,17 @@ * The main function of the ACI is to control the mixer and to get a * product identification. On the PCM20, ACI also controls the radio * tuner on this card, this is supported in the Video for Linux - * radio-miropcm20 driver. - * - * This Voxware ACI driver currently only supports the ACI functions - * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards - * with additional ACI functions can easily be added later. - * - * / NOTE / When compiling as a module, make sure to load the module - * after loading the mad16 module. The initialisation code expects the - * MAD16 default mixer to be already available. + * miropcm20 driver. + * - + * This is a fullfeatured implementation. Unsupported features + * are bugs... (: + * + * It is not longer necessary to load the mad16 module first. The + * user is currently responsible to set the mad16 mixer correctly. + * + * To toggle the solo mode for full duplex operation just use the OSS + * record switch for the pcm ('wave') controller. Robert + * - * * Revision history: * @@ -34,72 +36,78 @@ * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> * Small modification to export ACI functions and * complete modularisation. + * 2000-06-20 Robert Siemer <Robert.Siemer@gmx.de> + * Don't initialize the CS4231A mixer anymore, so the code is + * working again, and other small changes to fit in todays + * kernels. + * 2000-08-26 Robert Siemer + * Clean up and rewrite for 2.4.x. Maybe it's SMP safe now... (: + * ioctl bugfix, and integration of solo-mode into OSS-API, + * added (OSS-limited) equalizer support, return value bugfix, + * changed param aci_reset to reset, new params: ide, wss. */ -/* - * Some driver specific information and features: - * - * This mixer driver identifies itself to applications as "ACI" in - * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info). - * - * Proprietary mixer features that go beyond the standard OSS mixer - * interface are: - * - * Full duplex solo configuration: - * - * int solo_mode; - * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode); - * - * solo_mode = 0: deactivate solo mode (default) - * solo_mode > 0: activate solo mode - * With activated solo mode, the PCM input can not any - * longer hear the signals produced by the PCM output. - * Activating solo mode is important in duplex mode in order - * to avoid feedback distortions. - * solo_mode < 0: do not change solo mode (just retrieve the status) - * - * When the ioctl() returns 0, solo_mode contains the previous - * status (0 = deactivated, 1 = activated). If solo mode is not - * implemented on this card, ioctl() returns -1 and sets errno to - * EINVAL. - * - */ - +#include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> - +#include <linux/proc_fs.h> +#include <linux/slab.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include <asm/uaccess.h> #include "sound_config.h" -#undef DEBUG /* if defined, produce a verbose report via syslog */ +int aci_port; /* as determined by bit 4 in the OPTi 929 MC4 register */ +int aci_idcode[2]; /* manufacturer and product ID */ +int aci_version; /* ACI firmware version */ + +EXPORT_SYMBOL(aci_port); +EXPORT_SYMBOL(aci_idcode); +EXPORT_SYMBOL(aci_version); -int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */ -unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */ -unsigned char aci_version = 0; /* ACI firmware version */ -int aci_solo; /* status bit of the card that can't be * +#include "aci.h" + + +static int aci_solo=0; /* status bit of the card that can't be * + * checked with ACI versions prior to 0xb0 */ +static int aci_amp=0; /* status bit for power-amp/line-out level + but I have no docs about what is what... */ +static int aci_micpreamp=3; /* microphone preamp-level that can't be * * checked with ACI versions prior to 0xb0 */ -static int aci_present = 0; +static int mixer_device; +static struct semaphore aci_sem; -#ifdef MODULE /* Whether the aci mixer is to be reset. */ -int aci_reset = 0; /* Default: don't reset if the driver is a */ -MODULE_PARM(aci_reset,"i"); -#else /* module; use "insmod aci.o aci_reset=1" */ -int aci_reset = 1; /* to override. */ +#ifdef MODULE +static int reset = 0; +MODULE_PARM(reset,"i"); +MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer."); +#else +static int reset = 1; #endif +static int ide=-1; +MODULE_PARM(ide,"i"); +MODULE_PARM_DESC(ide,"1 enable, 0 disable ide-port - untested" + " default: do nothing"); +static int wss=-1; +MODULE_PARM(wss,"i"); +MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested" + " default: do nothing; for PCM1-pro only"); + +static void print_bits(unsigned char c) +{ + int j; + printk(KERN_DEBUG "aci: "); + + for (j=7; j>=0; j--) { + printk(KERN_DEBUG "%d", (c >> j) & 0x1); + } -#define COMMAND_REGISTER (aci_port) -#define STATUS_REGISTER (aci_port + 1) -#define BUSY_REGISTER (aci_port + 2) + printk(KERN_DEBUG "\n"); +} /* - * Wait until the ACI microcontroller has set the READYFLAG in the - * Busy/IRQ Source Register to 0. This is required to avoid - * overrunning the sound card microcontroller. We do a busy wait here, - * because the microcontroller is not supposed to signal a busy - * condition for more than a few clock cycles. In case of a time-out, - * this function returns -1. - * * This busy wait code normally requires less than 15 loops and * practically always less than 100 loops on my i486/DX2 66 MHz. * @@ -107,459 +115,476 @@ * function can take a VERY long time, because the PCM12 does some kind * of fade-in effect. For this reason, access to the MUTE function has * not been implemented at all. + * + * - The OSS interface has no mute option. It takes about 3 seconds to + * fade-in on my PCM20. busy_wait() handles it great now... Robert */ static int busy_wait(void) { + #define MINTIME 500 long timeout; + unsigned char byte; - for (timeout = 0; timeout < 10000000L; timeout++) - if ((inb_p(BUSY_REGISTER) & 1) == 0) - return 0; - -#ifdef DEBUG - printk("ACI: READYFLAG timed out.\n"); -#endif - - return -1; -} - - -/* - * Read the GENERAL STATUS register. - */ - -static int read_general_status(void) -{ - unsigned long flags; - int status; - - save_flags(flags); - cli(); - - if (busy_wait()) { - restore_flags(flags); - return -1; + for (timeout = 1; timeout <= MINTIME+30; timeout++) { + if (((byte=inb(BUSY_REGISTER)) & 1) == 0) { + if (timeout >= MINTIME) + printk(KERN_DEBUG "aci: Got READYFLAG in round %ld.\n", timeout-MINTIME); + return byte; + } + if (timeout >= MINTIME) { + long out=10*HZ; + switch (timeout-MINTIME) { + case 0 ... 9: + out /= 10; + case 10 ... 19: + out /= 10; + case 20 ... 30: + out /= 10; + default: + current->state=TASK_UNINTERRUPTIBLE; + schedule_timeout(out); + break; + } + } } - - status = (unsigned) inb_p(STATUS_REGISTER); - restore_flags(flags); - return status; + printk(KERN_WARNING "aci: busy_wait() time out.\n"); + return -EBUSY; } +/* The four ACI command types are fucked up. [-: + * implied is: 1w - special case for INIT + * write is: 2w1r + * read is: x(1w1r) where x is 1 or 2 (1 CHECK_SIG, 1 CHECK_STER, + * 1 VERSION, 2 IDCODE) + * the command is only in the first write, rest is protocol overhead + * + * indexed is technically a write and used for STATUS + * and the special case for TUNE is: 3w1r + * + * Here the new general sheme: TUNE --> aci_rw_cmd(x, y, z) + * indexed and write --> aci_rw_cmd(x, y, -1) + * implied and read (x=1) --> aci_rw_cmd(x, -1, -1) + * + * Read (x>=2) is not implemented (only used during initialization). + * Use aci_idcode[2] and aci_version... Robert + */ -/* - * The four ACI command types (implied, write, read and indexed) can - * be sent to the microcontroller using the following four functions. - * If a problem occurred, they return -1. +/* Some notes for error detection: theoretically it is possible. + * But it doubles the I/O-traffic from ww(r) to wwwrw(r) in the normal + * case and doesn't seem to be designed for that... Robert */ -int aci_implied_cmd(unsigned char opcode) +static inline int aci_rawwrite(unsigned char byte) { - unsigned long flags; - -#ifdef DEBUG - printk("ACI: aci_implied_cmd(0x%02x)\n", opcode); + if (busy_wait() >= 0) { +#if DEBUG + printk(KERN_DEBUG "aci_rawwrite(%d)\n", byte); #endif - - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(opcode, COMMAND_REGISTER); - - restore_flags(flags); - return 0; + outb(byte, COMMAND_REGISTER); + return 0; + } else + return -EBUSY; } - -int aci_write_cmd(unsigned char opcode, unsigned char parameter) +static inline int aci_rawread(void) { - unsigned long flags; - int status; + unsigned char byte; -#ifdef DEBUG - printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter); + if (busy_wait() >= 0) { + byte=inb(STATUS_REGISTER); +#if DEBUG + printk(KERN_DEBUG "%d = aci_rawread()\n", byte); #endif + return byte; + } else + return -EBUSY; +} - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } +int aci_rw_cmd(int write1, int write2, int write3) +{ + int write[] = {write1, write2, write3}; + int read, i; - outb_p(parameter, COMMAND_REGISTER); + if (down_interruptible(&aci_sem)) + return -EINTR; - if ((status = read_general_status()) < 0) { - restore_flags(flags); - return -1; + for (i=0; i<3; i++) { + if (write[i]< 0 || write[i] > 255) + break; + else + if (aci_rawwrite(write[i])<0) { + up(&aci_sem); + return -EBUSY; + } } - - /* polarity of the INVALID flag depends on ACI version */ - if ((aci_version < 0xb0 && (status & 0x40) != 0) || - (aci_version >= 0xb0 && (status & 0x40) == 0)) { - restore_flags(flags); - printk("ACI: invalid write command 0x%02x, 0x%02x.\n", - opcode, parameter); - return -1; + + if ((read=aci_rawread())<0) { + up(&aci_sem); + return -EBUSY; } - restore_flags(flags); - return 0; + up(&aci_sem); + return read; } -/* - * This write command send 2 parameters instead of one. - * Only used in PCM20 radio frequency tuning control - */ +EXPORT_SYMBOL(aci_rw_cmd); -int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2) +static int setvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - unsigned long flags; - int status; + int vol, ret, uservol, buf; -#ifdef DEBUG - printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2); -#endif - - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } + __get_user(uservol, (int *)arg); - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } + /* left channel */ + vol = uservol & 0xff; + if (vol > 100) + vol = 100; + vol = SCALE(100, 0x20, vol); + if ((buf=aci_write_cmd(left_index, 0x20 - vol))<0) + return buf; + ret = SCALE(0x20, 100, vol); - outb_p(parameter, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(parameter2, COMMAND_REGISTER); - - if ((status = read_general_status()) < 0) { - restore_flags(flags); - return -1; - } - - /* polarity of the INVALID flag depends on ACI version */ - if ((aci_version < 0xb0 && (status & 0x40) != 0) || - (aci_version >= 0xb0 && (status & 0x40) == 0)) { - restore_flags(flags); -#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */ - printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n", - opcode, parameter, parameter2); -#endif - return -1; - } - - restore_flags(flags); - return 0; -} -int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter) -{ - unsigned long flags; - int i = 0; - - save_flags(flags); - cli(); + /* right channel */ + vol = (uservol >> 8) & 0xff; + if (vol > 100) + vol = 100; + vol = SCALE(100, 0x20, vol); + if ((buf=aci_write_cmd(right_index, 0x20 - vol))<0) + return buf; + ret |= SCALE(0x20, 100, vol) << 8; - if (read_general_status() < 0) { - restore_flags(flags); - return -1; - } - while (i < length) { - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - parameter[i++] = inb_p(STATUS_REGISTER); -#ifdef DEBUG - if (i == 1) - printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n", - opcode, length, parameter[i-1]); - else - printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]); -#endif - } + __put_user(ret, (int *)arg); - restore_flags(flags); return 0; } - -int aci_indexed_cmd(unsigned char opcode, unsigned char index, - unsigned char *parameter) +static int getvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - unsigned long flags; + int vol; + int buf; - save_flags(flags); - cli(); - - if (read_general_status() < 0 || busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(opcode, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } - - outb_p(index, COMMAND_REGISTER); - if (busy_wait()) { - restore_flags(flags); - return -1; - } + /* left channel */ + if ((buf=aci_indexed_cmd(0xf0, left_index))<0) + return buf; + vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); - *parameter = inb_p(STATUS_REGISTER); -#ifdef DEBUG - printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index, - *parameter); -#endif + /* right channel */ + if ((buf=aci_indexed_cmd(0xf0, right_index))<0) + return buf; + vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; + + __put_user(vol, (int *)arg); - restore_flags(flags); return 0; } -/* - * The following macro SCALE can be used to scale one integer volume - * value into another one using only integer arithmetic. If the input - * value x is in the range 0 <= x <= xmax, then the result will be in - * the range 0 <= SCALE(xmax,ymax,x) <= ymax. - * - * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the - * following nice properties: - * - * - SCALE(xmax,ymax,xmax) = ymax - * - SCALE(xmax,ymax,0) = 0 - * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) - * - * In addition, the rounding error is minimal and nicely distributed. - * The proofs are left as an exercise to the reader. +/* The equalizer is somewhat strange on the ACI. From -12dB to +12dB + * write: 0xff..down.to..0x80==0x00..up.to..0x7f */ -#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax)) +static inline unsigned int eq_oss2aci(unsigned int vol) +{ + int boost=0; + unsigned int ret; + + if (vol > 100) + vol = 100; + if (vol > 50) { + vol -= 51; + boost=1; + } + if (boost) + ret=SCALE(49, 0x7e, vol)+1; + else + ret=0xff - SCALE(50, 0x7f, vol); + return ret; +} + +static inline unsigned int eq_aci2oss(unsigned int vol) +{ + if (vol < 0x80) + return SCALE(0x7f, 50, vol) + 50; + else + return SCALE(0x7f, 50, 0xff-vol); +} -static int getvolume(caddr_t arg, - unsigned char left_index, unsigned char right_index) +static int setequalizer(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - int vol; - unsigned char buf; + int buf; + unsigned int vol; + + __get_user(vol, (int *)arg); /* left channel */ - if (aci_indexed_cmd(0xf0, left_index, &buf)) - return -EIO; - vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); - + if ((buf=aci_write_cmd(left_index, eq_oss2aci(vol & 0xff)))<0) + return buf; + /* right channel */ - if (aci_indexed_cmd(0xf0, right_index, &buf)) - return -EIO; - vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; + if ((buf=aci_write_cmd(right_index, eq_oss2aci((vol>>8) & 0xff)))<0) + return buf; - return (*(int *) arg = vol); + /* the ACI equalizer is more precise */ + return 0; } - -static int setvolume(caddr_t arg, - unsigned char left_index, unsigned char right_index) +static int getequalizer(caddr_t arg, + unsigned char left_index, unsigned char right_index) { - int vol, ret; + int buf; + unsigned int vol; /* left channel */ - vol = *(int *)arg & 0xff; - if (vol > 100) - vol = 100; - vol = SCALE(100, 0x20, vol); - if (aci_write_cmd(left_index, 0x20 - vol)) - return -EIO; - ret = SCALE(0x20, 100, vol); + if ((buf=aci_indexed_cmd(0xf0, left_index))<0) + return buf; + vol = eq_aci2oss(buf); + + /* right channel */ + if ((buf=aci_indexed_cmd(0xf0, right_index))<0) + return buf; + vol |= eq_aci2oss(buf) << 8; + __put_user(vol, (int *)arg); - /* right channel */ - vol = (*(int *)arg >> 8) & 0xff; - if (vol > 100) - vol = 100; - vol = SCALE(100, 0x20, vol); - if (aci_write_cmd(right_index, 0x20 - vol)) - return -EIO; - ret |= SCALE(0x20, 100, vol) << 8; - - return (*(int *) arg = ret); + return 0; } - -static int -aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { - int status, vol; - unsigned char buf; + int vol, buf; - /* handle solo mode control */ - if (cmd == SOUND_MIXER_PRIVATE1) { - if (*(int *) arg >= 0) { - aci_solo = !!*(int *) arg; - if (aci_write_cmd(0xd2, aci_solo)) - return -EIO; - } else if (aci_version >= 0xb0) { - if ((status = read_general_status()) < 0) - return -EIO; - return (*(int *) arg = (status & 0x20) == 0); + switch (cmd) { + case SOUND_MIXER_WRITE_VOLUME: + return setvolume(arg, 0x01, 0x00); + case SOUND_MIXER_WRITE_CD: + return setvolume(arg, 0x3c, 0x34); + case SOUND_MIXER_WRITE_MIC: + return setvolume(arg, 0x38, 0x30); + case SOUND_MIXER_WRITE_LINE: + return setvolume(arg, 0x39, 0x31); + case SOUND_MIXER_WRITE_SYNTH: + return setvolume(arg, 0x3b, 0x33); + case SOUND_MIXER_WRITE_PCM: + return setvolume(arg, 0x3a, 0x32); + case MIXER_WRITE(SOUND_MIXER_RADIO): /* fall through */ + case SOUND_MIXER_WRITE_LINE1: /* AUX1 or radio */ + return setvolume(arg, 0x3d, 0x35); + case SOUND_MIXER_WRITE_LINE2: /* AUX2 */ + return setvolume(arg, 0x3e, 0x36); + case SOUND_MIXER_WRITE_BASS: /* set band one and two */ + if (aci_idcode[1]=='C') { + if ((buf=setequalizer(arg, 0x48, 0x40)) || + (buf=setequalizer(arg, 0x49, 0x41))); + return buf; } - - return (*(int *) arg = aci_solo); - } - - if (((cmd >> 8) & 0xff) == 'M') { - if (cmd & SIOC_IN) - /* read and write */ - switch (cmd & 0xff) { - case SOUND_MIXER_VOLUME: - return setvolume(arg, 0x01, 0x00); - case SOUND_MIXER_CD: - return setvolume(arg, 0x3c, 0x34); - case SOUND_MIXER_MIC: - return setvolume(arg, 0x38, 0x30); - case SOUND_MIXER_LINE: - return setvolume(arg, 0x39, 0x31); - case SOUND_MIXER_SYNTH: - return setvolume(arg, 0x3b, 0x33); - case SOUND_MIXER_PCM: - return setvolume(arg, 0x3a, 0x32); - case SOUND_MIXER_LINE1: /* AUX1 */ - return setvolume(arg, 0x3d, 0x35); - case SOUND_MIXER_LINE2: /* AUX2 */ - return setvolume(arg, 0x3e, 0x36); - case SOUND_MIXER_IGAIN: /* MIC pre-amp */ - vol = *(int *) arg & 0xff; - if (vol > 100) - vol = 100; - vol = SCALE(100, 3, vol); - if (aci_write_cmd(0x03, vol)) - return -EIO; - vol = SCALE(3, 100, vol); - return (*(int *) arg = vol | (vol << 8)); - case SOUND_MIXER_RECSRC: - return (*(int *) arg = 0); - break; - default: - return -EINVAL; + break; + case SOUND_MIXER_WRITE_TREBLE: /* set band six and seven */ + if (aci_idcode[1]=='C') { + if ((buf=setequalizer(arg, 0x4d, 0x45)) || + (buf=setequalizer(arg, 0x4e, 0x46))); + return buf; + } + break; + case SOUND_MIXER_WRITE_IGAIN: /* MIC pre-amp */ + if (aci_idcode[1]=='B' || aci_idcode[1]=='C') { + __get_user(vol, (int *)arg); + vol = vol & 0xff; + if (vol > 100) + vol = 100; + vol = SCALE(100, 3, vol); + if ((buf=aci_write_cmd(0x03, vol))<0) + return buf; + aci_micpreamp = vol; + vol = SCALE(3, 100, vol); + vol |= (vol << 8); + __put_user(vol, (int *)arg); + return 0; + } + break; + case SOUND_MIXER_WRITE_OGAIN: /* Power-amp/line-out level */ + if (aci_idcode[1]=='A' || aci_idcode[1]=='B') { + __get_user(buf, (int *)arg); + buf = buf & 0xff; + if (buf > 50) + vol = 1; + else + vol = 0; + if ((buf=aci_write_cmd(0x0f, vol))<0) + return buf; + aci_amp = vol; + if (aci_amp) + buf = (100 || 100<<8); + else + buf = 0; + __put_user(buf, (int *)arg); + return 0; + } + break; + case SOUND_MIXER_WRITE_RECSRC: + /* handle solo mode control */ + __get_user(buf, (int *)arg); + /* unset solo when RECSRC for PCM is requested */ + if (aci_idcode[1]=='B' || aci_idcode[1]=='C') { + vol = !(buf & SOUND_MASK_PCM); + if ((buf=aci_write_cmd(0xd2, vol))<0) + return buf; + aci_solo = vol; + } + buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE| + SOUND_MASK_SYNTH| SOUND_MASK_LINE2); + if (aci_idcode[1] == 'C') /* PCM20 radio */ + buf |= SOUND_MASK_RADIO; + else + buf |= SOUND_MASK_LINE1; + if (!aci_solo) + buf |= SOUND_MASK_PCM; + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_DEVMASK: + buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | + SOUND_MASK_LINE2); + switch (aci_idcode[1]) { + case 'C': /* PCM20 radio */ + buf |= (SOUND_MASK_RADIO | SOUND_MASK_IGAIN | + SOUND_MASK_BASS | SOUND_MASK_TREBLE); + break; + case 'B': /* PCM12 */ + buf |= (SOUND_MASK_LINE1 | SOUND_MASK_IGAIN | + SOUND_MASK_OGAIN); + break; + case 'A': /* PCM1-pro */ + buf |= (SOUND_MASK_LINE1 | SOUND_MASK_OGAIN); + break; + default: + buf |= SOUND_MASK_LINE1; + } + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_STEREODEVS: + buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | + SOUND_MASK_LINE2); + switch (aci_idcode[1]) { + case 'C': /* PCM20 radio */ + buf |= (SOUND_MASK_RADIO | + SOUND_MASK_BASS | SOUND_MASK_TREBLE); + break; + default: + buf |= SOUND_MASK_LINE1; + } + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_RECMASK: + buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE| + SOUND_MASK_SYNTH| SOUND_MASK_LINE2| SOUND_MASK_PCM); + if (aci_idcode[1] == 'C') /* PCM20 radio */ + buf |= SOUND_MASK_RADIO; + else + buf |= SOUND_MASK_LINE1; + + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_RECSRC: + buf = (SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_LINE2); + /* do we need aci_solo or can I get it from the ACI? */ + switch (aci_idcode[1]) { + case 'B': /* PCM12 */ + case 'C': /* PCM20 radio */ + if (aci_version >= 0xb0) { + if ((vol=aci_rw_cmd(0xf0, 0x00, -1))<0) + return vol; + if (vol & 0x20) + buf |= SOUND_MASK_PCM; } + else + if (!aci_solo) + buf |= SOUND_MASK_PCM; + break; + default: + buf |= SOUND_MASK_PCM; + } + if (aci_idcode[1] == 'C') /* PCM20 radio */ + buf |= SOUND_MASK_RADIO; else - /* only read */ - switch (cmd & 0xff) { - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = - SOUND_MASK_VOLUME | SOUND_MASK_CD | - SOUND_MASK_MIC | SOUND_MASK_LINE | - SOUND_MASK_SYNTH | SOUND_MASK_PCM | -#if 0 - SOUND_MASK_IGAIN | -#endif - SOUND_MASK_LINE1 | SOUND_MASK_LINE2); - break; - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = - SOUND_MASK_VOLUME | SOUND_MASK_CD | - SOUND_MASK_MIC | SOUND_MASK_LINE | - SOUND_MASK_SYNTH | SOUND_MASK_PCM | - SOUND_MASK_LINE1 | SOUND_MASK_LINE2); - break; - case SOUND_MIXER_RECMASK: - return (*(int *) arg = 0); - break; - case SOUND_MIXER_RECSRC: - return (*(int *) arg = 0); - break; - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); - break; - case SOUND_MIXER_VOLUME: - return getvolume(arg, 0x04, 0x03); - case SOUND_MIXER_CD: - return getvolume(arg, 0x0a, 0x09); - case SOUND_MIXER_MIC: - return getvolume(arg, 0x06, 0x05); - case SOUND_MIXER_LINE: - return getvolume(arg, 0x08, 0x07); - case SOUND_MIXER_SYNTH: - return getvolume(arg, 0x0c, 0x0b); - case SOUND_MIXER_PCM: - return getvolume(arg, 0x0e, 0x0d); - case SOUND_MIXER_LINE1: /* AUX1 */ - return getvolume(arg, 0x11, 0x10); - case SOUND_MIXER_LINE2: /* AUX2 */ - return getvolume(arg, 0x13, 0x12); - case SOUND_MIXER_IGAIN: /* MIC pre-amp */ - if (aci_indexed_cmd(0xf0, 0x21, &buf)) - return -EIO; - vol = SCALE(3, 100, buf <= 3 ? buf : 3); - vol |= vol << 8; - return (*(int *) arg = vol); - default: - return -EINVAL; + buf |= SOUND_MASK_LINE1; + + __put_user(buf, (int *)arg); + return 0; + case SOUND_MIXER_READ_CAPS: + __put_user(0, (int *)arg); + return 0; + case SOUND_MIXER_READ_VOLUME: + return getvolume(arg, 0x04, 0x03); + case SOUND_MIXER_READ_CD: + return getvolume(arg, 0x0a, 0x09); + case SOUND_MIXER_READ_MIC: + return getvolume(arg, 0x06, 0x05); + case SOUND_MIXER_READ_LINE: + return getvolume(arg, 0x08, 0x07); + case SOUND_MIXER_READ_SYNTH: + return getvolume(arg, 0x0c, 0x0b); + case SOUND_MIXER_READ_PCM: + return getvolume(arg, 0x0e, 0x0d); + case MIXER_READ(SOUND_MIXER_RADIO): /* fall through */ + case SOUND_MIXER_READ_LINE1: /* AUX1 */ + return getvolume(arg, 0x11, 0x10); + case SOUND_MIXER_READ_LINE2: /* AUX2 */ + return getvolume(arg, 0x13, 0x12); + case SOUND_MIXER_READ_BASS: /* get band one */ + if (aci_idcode[1]=='C') { + return getequalizer(arg, 0x23, 0x22); + } + break; + case SOUND_MIXER_READ_TREBLE: /* get band seven */ + if (aci_idcode[1]=='C') { + return getequalizer(arg, 0x2f, 0x2e); + } + break; + case SOUND_MIXER_READ_IGAIN: /* MIC pre-amp */ + if (aci_idcode[1]=='B' || aci_idcode[1]=='C') { + /* aci_micpreamp or ACI? */ + if (aci_version >= 0xb0) { + if ((buf=aci_indexed_cmd(0xf0, 0x21))<0) + return buf; } + else + buf=aci_micpreamp; + vol = SCALE(3, 100, buf <= 3 ? buf : 3); + vol |= vol << 8; + __put_user(vol, (int *)arg); + return 0; + } + break; + case SOUND_MIXER_READ_OGAIN: + if (aci_amp) + buf = (100 || 100<<8); + else + buf = 0; + __put_user(buf, (int *)arg); + return 0; } - return -EINVAL; } - static struct mixer_operations aci_mixer_operations = { - owner: THIS_MODULE, - id: "ACI", - name: "ACI mixer", - ioctl: aci_mixer_ioctl + owner: THIS_MODULE, + id: "ACI", + ioctl: aci_mixer_ioctl }; -static unsigned char -mad_read (int port) -{ - outb (0xE3, 0xf8f); /* Write MAD16 password */ - return inb (port); /* Read from port */ -} - - /* - * Check, whether there actually is any ACI port operational and if - * one was found, then initialize the ACI interface, reserve the I/O - * addresses and attach the new mixer to the relevant VoxWare data - * structures. - * - * Returns: 1 ACI mixer detected - * 0 nothing there - * * There is also an internal mixer in the codec (CS4231A or AD1845), * that deserves no purpose in an ACI based system which uses an * external ACI controlled stereo mixer. Make sure that this codec @@ -570,153 +595,108 @@ static int __init attach_aci(void) { - char *boardname = "unknown"; - int volume; + char *boardname; + int i; -#define MC4_PORT 0xf90 + init_MUTEX(&aci_sem); - aci_port = - (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354; + outb(0xE3, 0xf8f); /* Write MAD16 password */ + aci_port = (inb(0xf90) & 0x10) ? + 0x344: 0x354; /* Get aci_port from MC4_PORT */ if (check_region(aci_port, 3)) { -#ifdef DEBUG - printk("ACI: I/O area 0x%03x-0x%03x already used.\n", - aci_port, aci_port+2); -#endif - return 0; + printk(KERN_NOTICE "aci: I/O area 0x%03x-0x%03x already used.\n", + aci_port, aci_port+2); + return -EBUSY; } - - if (aci_read_cmd(0xf2, 2, aci_idcode)) { -#ifdef DEBUG - printk("ACI: Failed to read idcode.\n"); -#endif - return 0; + + /* force ACI into a known state */ + for (i=0; i<3; i++) + if (aci_rw_cmd(0xdf, -1, -1)<0) + return -EFAULT; + + /* official this is one aci read call: */ + if ((aci_idcode[0]=aci_rw_cmd(0xf2, -1, -1))<0 || + (aci_idcode[1]=aci_rw_cmd(0xf2, -1, -1))<0) { + printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port); + return -EFAULT; } - - if (aci_read_cmd(0xf1, 1, &aci_version)) { -#ifdef DEBUG - printk("ACI: Failed to read version.\n"); -#endif - return 0; + + if ((aci_version=aci_rw_cmd(0xf1, -1, -1))<0) { + printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port); + return -EFAULT; } - if (aci_idcode[0] == 0x6d) { + if (aci_idcode[0] == 'm') { /* It looks like a miro sound card. */ switch (aci_idcode[1]) { - case 0x41: - boardname = "PCM1 pro / early PCM12"; - break; - case 0x42: - boardname = "PCM12"; - break; - case 0x43: - boardname = "PCM20"; - break; - default: - boardname = "unknown miro"; + case 'A': + boardname = "PCM1 pro / early PCM12"; + break; + case 'B': + boardname = "PCM12"; + break; + case 'C': + boardname = "PCM20 radio"; + break; + default: + boardname = "unknown miro"; } - } else -#ifndef DEBUG - return 0; -#endif - - printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n", - aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port); - - if (aci_reset) { - /* initialize ACI mixer */ - aci_implied_cmd(0xff); - aci_solo = 0; - } - - /* attach the mixer */ - request_region(aci_port, 3, "sound mixer (ACI)"); - if (num_mixers < MAX_MIXER_DEV) { - if (num_mixers > 0 && - !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) { - /* - * The previously registered mixer device is the CS4231A which - * has no function on an ACI card. Make the ACI mixer the first - * of the two mixer devices. - */ - mixer_devs[num_mixers] = mixer_devs[num_mixers-1]; - mixer_devs[num_mixers-1] = &aci_mixer_operations; - /* - * Initialize the CS4231A mixer with reasonable values. It is - * unlikely that the user ever will want to change these as all - * channels can be mixed via ACI. - */ - volume = 0x6464; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); - volume = 0x6464; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); - volume = 0; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume); - volume = SOUND_MASK_LINE1; - mixer_devs[num_mixers]->ioctl(num_mixers, - SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume); - num_mixers++; - } else - mixer_devs[num_mixers++] = &aci_mixer_operations; - } - - /* Just do something; otherwise the first write command fails, at - * least with my PCM20. - */ - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume); - - if (aci_reset) { - /* Initialize ACI mixer with reasonable power-up values */ - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); - volume = 0x3232; - aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); + } else { + printk(KERN_WARNING "aci: Warning: unsupported card! - " + "no hardware, no specs...\n"); + boardname = "unknown Cardinal Technologies"; + } + + printk(KERN_INFO "<ACI 0x%02x, id %02x/%02x \"%c/%c\", (%s)> at 0x%03x\n", + aci_version, + aci_idcode[0], aci_idcode[1], + aci_idcode[0], aci_idcode[1], + boardname, aci_port); + + if (reset) { + /* first write()s after reset fail with my PCM20 */ + if (aci_rw_cmd(0xff, -1, -1)<0 || + aci_rw_cmd(0xdf, 0xdf, 0xdf)<0 || + aci_rw_cmd(0xdf, 0xdf, 0xdf)<0) + return -EBUSY; + } + + /* the PCM20 is muted after reset (and reboot) */ + if (aci_rw_cmd(0x0d, 0x00, -1)<0) + return -EBUSY; + + if (ide>=0) + if (aci_rw_cmd(0xd0, !ide, -1)<0) + return -EBUSY; + + if (wss>=0 && aci_idcode[1]=='A') + if (aci_rw_cmd(0xd1, !!wss, -1)<0) + return -EBUSY; + + if (!request_region(aci_port, 3, "sound mixer (ACI)")) + return -ENOMEM; + + if ((mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, + boardname, + &aci_mixer_operations, + sizeof(aci_mixer_operations), + NULL)) >= 0) { + /* Maybe initialize the CS4231A mixer here... */ + } else { + printk(KERN_ERR "aci: Failed to install mixer.\n"); + release_region(aci_port, 3); + return mixer_device; } - aci_present = 1; - - return 1; + return 0; } static void __exit unload_aci(void) { - if (aci_present) - release_region(aci_port, 3); + sound_unload_mixerdev(mixer_device); + release_region(aci_port, 3); } - -EXPORT_SYMBOL(aci_write_cmd); -EXPORT_SYMBOL(aci_indexed_cmd); -EXPORT_SYMBOL(aci_write_cmd_d); module_init(attach_aci); module_exit(unload_aci); diff -u --recursive --new-file v2.4.3/linux/drivers/sound/aci.h linux/drivers/sound/aci.h --- v2.4.3/linux/drivers/sound/aci.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/aci.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,55 @@ +#ifndef _ACI_H_ +#define _ACI_H_ + +extern int aci_port; +extern int aci_idcode[2]; /* manufacturer and product ID */ +extern int aci_version; /* ACI firmware version */ +extern int aci_rw_cmd(int write1, int write2, int write3); + +extern char * aci_radio_name; +extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize); + +#define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1) +#define aci_write_cmd(a, b) aci_rw_cmd(a, b, -1) +#define aci_read_cmd(a) aci_rw_cmd(a,-1, -1) + +#define COMMAND_REGISTER (aci_port) /* write register */ +#define STATUS_REGISTER (aci_port + 1) /* read register */ +#define BUSY_REGISTER (aci_port + 2) /* also used for rds */ + +#define RDS_REGISTER BUSY_REGISTER + +#define RDS_STATUS 0x01 +#define RDS_STATIONNAME 0x02 +#define RDS_TEXT 0x03 +#define RDS_ALTFREQ 0x04 +#define RDS_TIMEDATE 0x05 +#define RDS_PI_CODE 0x06 +#define RDS_PTYTATP 0x07 +#define RDS_RESET 0x08 +#define RDS_RXVALUE 0x09 + +/* + * The following macro SCALE can be used to scale one integer volume + * value into another one using only integer arithmetic. If the input + * value x is in the range 0 <= x <= xmax, then the result will be in + * the range 0 <= SCALE(xmax,ymax,x) <= ymax. + * + * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the + * following nice properties: + * + * - SCALE(xmax,ymax,xmax) = ymax + * - SCALE(xmax,ymax,0) = 0 + * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) + * + * In addition, the rounding error is minimal and nicely distributed. + * The proofs are left as an exercise to the reader. + */ + +#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax)) + +extern void __exit unload_aci_rds(void); +extern int __init attach_aci_rds(void); + + +#endif /* _ACI_H_ */ diff -u --recursive --new-file v2.4.3/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c --- v2.4.3/linux/drivers/sound/aedsp16.c Wed Sep 27 13:53:57 2000 +++ linux/drivers/sound/aedsp16.c Fri Apr 13 20:26:07 2001 @@ -257,9 +257,9 @@ #define VERSION "1.3" /* Version of Audio Excel DSP 16 driver */ -#undef AEDSP16_DEBUG 1 /* Define this to enable debug code */ -#undef AEDSP16_DEBUG_MORE 1 /* Define this to enable more debug */ -#undef AEDSP16_INFO 1 /* Define this to enable info code */ +#undef AEDSP16_DEBUG /* Define this to 1 to enable debug code */ +#undef AEDSP16_DEBUG_MORE /* Define this to 1 to enable more debug */ +#undef AEDSP16_INFO /* Define this to 1 to enable info code */ #if defined(AEDSP16_DEBUG) # define DBG(x) printk x diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c --- v2.4.3/linux/drivers/sound/cs4281/cs4281m.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/sound/cs4281/cs4281m.c Fri Apr 6 10:51:19 2001 @@ -4289,6 +4289,11 @@ CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO "cs4281: probe()+\n")); + if (pci_enable_device(pcidev)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs4281: pci_enable_device() failed\n")); + return -1; + } if (!RSRCISMEMORYREGION(pcidev, 0) || !RSRCISMEMORYREGION(pcidev, 1)) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR @@ -4366,11 +4371,6 @@ s->magic = CS4281_MAGIC; s->pcidev = pcidev; s->irq = pcidev->irq; - if (pci_enable_device(pcidev)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4281: pci_enable_device() failed\n")); - goto err_irq; - } if (request_irq (s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)) { CS_DBGOUT(CS_INIT | CS_ERROR, 1, diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs461x.h linux/drivers/sound/cs461x.h --- v2.4.3/linux/drivers/sound/cs461x.h Tue Aug 22 11:31:05 2000 +++ linux/drivers/sound/cs461x.h Wed Apr 11 19:02:37 2001 @@ -2,6 +2,7 @@ #define __CS461X_H /* + * Copyright (c) by Cirrus Logic Corporation <pcaudio@crystal.cirrus.com> * Copyright (c) by Jaroslav Kysela <perex@suse.cz> * Definitions for Cirrus Logic CS461x chips * @@ -1614,4 +1615,77 @@ #define CS461X_MODE_OUTPUT (1<<0) /* MIDI UART - output */ #define CS461X_MODE_INPUT (1<<1) /* MIDI UART - input */ +//**************************************************************************** +// +// The following define the offsets of the AC97 shadow registers, which appear +// as a virtual extension to the base address register zero memory range. +// +//**************************************************************************** +#define AC97_REG_OFFSET_MASK 0x0000007EL +#define AC97_CODEC_NUMBER_MASK 0x00003000L + +#define BA0_AC97_RESET 0x00001000L +#define BA0_AC97_MASTER_VOLUME 0x00001002L +#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L +#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L +#define BA0_AC97_MASTER_TONE 0x00001008L +#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL +#define BA0_AC97_PHONE_VOLUME 0x0000100CL +#define BA0_AC97_MIC_VOLUME 0x0000100EL +#define BA0_AC97_LINE_IN_VOLUME 0x00001010L +#define BA0_AC97_CD_VOLUME 0x00001012L +#define BA0_AC97_VIDEO_VOLUME 0x00001014L +#define BA0_AC97_AUX_VOLUME 0x00001016L +#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L +#define BA0_AC97_RECORD_SELECT 0x0000101AL +#define BA0_AC97_RECORD_GAIN 0x0000101CL +#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL +#define BA0_AC97_GENERAL_PURPOSE 0x00001020L +#define BA0_AC97_3D_CONTROL 0x00001022L +#define BA0_AC97_MODEM_RATE 0x00001024L +#define BA0_AC97_POWERDOWN 0x00001026L +#define BA0_AC97_EXT_AUDIO_ID 0x00001028L +#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL +#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL +#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL +#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L +#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L +#define BA0_AC97_MIC_ADC_RATE 0x00001034L +#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L +#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L +#define BA0_AC97_RESERVED_3A 0x0000103AL +#define BA0_AC97_EXT_MODEM_ID 0x0000103CL +#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL +#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L +#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L +#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L +#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L +#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L +#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL +#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL +#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL +#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L +#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L +#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L +#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L +#define BA0_AC97_RESERVED_58 0x00001058L +#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL +#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL +#define BA0_AC97_AC_MODE 0x0000105EL +#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L +#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L +#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L +#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L +#define BA0_AC97_SPDIF_CONTROL 0x00001068L +#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL +#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL +#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL +#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L +#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L +#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L +#define BA0_AC97_CAL_ADDRESS 0x00001076L +#define BA0_AC97_CAL_DATA 0x00001078L +#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL +#define BA0_AC97_VENDOR_ID1 0x0000107CL +#define BA0_AC97_VENDOR_ID2 0x0000107EL #endif /* __CS461X_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs461x_image.h linux/drivers/sound/cs461x_image.h --- v2.4.3/linux/drivers/sound/cs461x_image.h Wed Dec 6 16:13:33 2000 +++ linux/drivers/sound/cs461x_image.h Wed Apr 11 19:02:37 2001 @@ -1,9 +1,12 @@ /**************************************************************************** * "CWCIMAGE.H"-- For CS46XX. Ver 1.04 - * Copyright 1998-2000 (c) Cirrus Logic Corp. + * Copyright 1998-2001 (c) Cirrus Logic Corp. * Version 1.04 **************************************************************************** */ +#ifndef __CS_IMAGE_H +#define __CS_IMAGE_H + #define CLEAR__COUNT 3 #define FILL__COUNT 4 #define BA1__DWORD_SIZE 13*1024+512 @@ -314,3 +317,6 @@ {0x000137f0, sizeof(FillArray3), FillArray3}, {0x00020000, sizeof(FillArray4), FillArray4} }; + + +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.4.3/linux/drivers/sound/cs46xx.c Tue Mar 20 12:04:58 2001 +++ linux/drivers/sound/cs46xx.c Thu Apr 12 12:16:36 2001 @@ -1,7 +1,8 @@ /* * Crystal SoundFusion CS46xx driver * - * Copyright 1998-2000 Cirrus Logic Corporation <audio@crystal.cirrus.com> + * Copyright 1998-2001 Cirrus Logic Corporation <pcaudio@crystal.cirrus.com> + * <twoller@crystal.cirrus.com> * Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz> * Copyright 2000 Alan Cox <alan@redhat.com> * @@ -22,7 +23,6 @@ * 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. - * * Current maintainers: * Cirrus Logic Corporation, Thomas Woller (tw) * <twoller@crystal.cirrus.com> @@ -43,17 +43,33 @@ * underruns. * 20001201-tw add resyncing of swptr on underruns. * 20001205-tw-nf fixed GETOSPACE ioctl() after open() - * + * 20010113-tw patch from Hans Grobler general cleanup. + * 20010117-tw 2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0 + * 20010118-tw basic PM support for 2.2.16+ and 2.4.0/2.4.2. + * 20010228-dh patch from David Huggins - cs_update_ptr recursion. * * Status: * Playback/Capture supported from 8k-48k. * 16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported. + * + * APM/PM - 2.2.x APM is enabled and functioning fine. APM can also + * be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro + * definition. + * + * Hercules Game Pro XP - the EGPIO2 pin controls the external Amp, + * but the static image can not modify the EGPIO pins, so we can not + * turn on the external amp. + * + * VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control + * the external amplifier for the "back" speakers, since we do not + * support the secondary codec then this external amp is also not + * turned on. */ -#include <linux/module.h> +#include <linux/list.h> #include <linux/version.h> +#include <linux/module.h> #include <linux/string.h> -#include <linux/ctype.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/delay.h> @@ -61,22 +77,21 @@ #include <linux/slab.h> #include <linux/soundcard.h> #include <linux/pci.h> -#ifdef CS46XX_PM -#include <linux/pm.h> -#endif +#include <linux/bitops.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/init.h> #include <linux/poll.h> -#include <linux/spinlock.h> -#include <linux/ac97_codec.h> +#include <linux/smp_lock.h> #include <linux/wrapper.h> #include <asm/uaccess.h> #include <asm/hardirq.h> +#include <linux/ac97_codec.h> +#include "cs46xxpm-24.h" +#include "cs46xx_wrapper-24.h" #include "cs461x.h" - /* MIDI buffer sizes */ #define CS_MIDIINBUF 500 #define CS_MIDIOUTBUF 500 @@ -90,6 +105,11 @@ #define CS_TYPE_ADC 1 #define CS_TYPE_DAC 2 + +#define CS_TRUE 1 +#define CS_FALSE 0 + +#define CS_DBGBREAKPOINT {__asm__("INT $3");} /* * CS461x definitions */ @@ -135,14 +155,22 @@ #define CS_RELEASE 0x00000800 /* all release functions in the driver */ #define CS_PARMS 0x00001000 /* functional and operational parameters */ #define CS_IOCTL 0x00002000 /* ioctl (non-mixer) */ +#define CS_PM 0x00004000 /* PM */ #define CS_TMP 0x10000000 /* tmp debug mask bit */ +#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend +#define CS_IOCTL_CMD_RESUME 0x2 // resume + #if CSDEBUG static unsigned long cs_debuglevel=1; /* levels range from 1-9 */ MODULE_PARM(cs_debuglevel, "i"); static unsigned long cs_debugmask=CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */ MODULE_PARM(cs_debugmask, "i"); #endif +static unsigned long initdelay=700; /* PM delay in millisecs */ +MODULE_PARM(initdelay, "i"); +static unsigned long powerdown=1; /* turn on/off powerdown processing in driver */ +MODULE_PARM(powerdown, "i"); #define DMABUF_DEFAULTORDER 3 static unsigned long defaultorder=DMABUF_DEFAULTORDER; MODULE_PARM(defaultorder, "i"); @@ -153,7 +181,6 @@ MODULE_PARM(thinkpad, "i"); /* An instance of the 4610 channel */ - struct cs_channel { int used; @@ -161,7 +188,16 @@ void *state; }; -#define DRIVER_VERSION "1.10" +#define CS46XX_MAJOR_VERSION "1" +#define CS46XX_MINOR_VERSION "22" + +#ifdef __ia64__ +#define CS46XX_ARCH "64" //architecture key +#else +#define CS46XX_ARCH "32" //architecture key +#endif + +struct list_head cs46xx_devs = { &cs46xx_devs, &cs46xx_devs }; /* magic numbers to protect our data structures */ #define CS_CARD_MAGIC 0x43525553 /* "CRUS" */ @@ -208,7 +244,8 @@ unsigned divisor; unsigned type; void *tmpbuff; /* tmp buffer for sample conversions */ - dma_addr_t dma_handle_tmpbuff; + dma_addr_t dmaaddr; + dma_addr_t dmaaddr_tmpbuff; unsigned buforder_tmpbuff; /* Log base 2 of size in bytes.. */ /* our buffer acts like a circular ring */ @@ -239,7 +276,6 @@ } dmabuf; }; - struct cs_card { struct cs_channel channel[2]; unsigned int magic; @@ -253,6 +289,7 @@ /* PCI device stuff */ struct pci_dev * pci_dev; + struct list_head list; unsigned int pctl, cctl; /* Hardware DMA flag sets */ @@ -268,6 +305,7 @@ int amplifier; /* Amplifier control */ void (*amplifier_ctrl)(struct cs_card *, int); + void (*amp_init)(struct cs_card *); int active; /* Active clocking */ void (*active_ctrl)(struct cs_card *, int); @@ -309,15 +347,17 @@ mode_t open_mode; struct semaphore open_sem; } midi; + struct cs46xx_pm pm; }; -static struct cs_card *devs; - static int cs_open_mixdev(struct inode *inode, struct file *file); static int cs_release_mixdev(struct inode *inode, struct file *file); static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static loff_t cs_llseek(struct file *file, loff_t offset, int origin); +static int cs_hardware_init(struct cs_card *card); +static int cs46xx_powerup(struct cs_card *card, unsigned int type); +static int cs461x_powerdown(struct cs_card *card, unsigned int type); static inline unsigned ld2(unsigned int x) { @@ -352,13 +392,9 @@ #define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) #define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) #define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) +#define SOUND_MIXER_CS_APM _SIOWR('M',124, int) -#define SNDCTL_DSP_CS_GETDBGLEVEL _SIOWR('P', 50, int) -#define SNDCTL_DSP_CS_SETDBGLEVEL _SIOWR('P', 51, int) -#define SNDCTL_DSP_CS_GETDBGMASK _SIOWR('P', 52, int) -#define SNDCTL_DSP_CS_SETDBGMASK _SIOWR('P', 53, int) - -static void printioctl(unsigned int x) +void printioctl(unsigned int x) { unsigned int i; unsigned char vidx; @@ -477,18 +513,6 @@ case SOUND_PCM_READ_FILTER: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") ); break; - case SNDCTL_DSP_CS_GETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_GETDBGMASK: ") ); - break; - case SNDCTL_DSP_CS_GETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_GETDBGLEVEL: ") ); - break; - case SNDCTL_DSP_CS_SETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_SETDBGMASK: ") ); - break; - case SNDCTL_DSP_CS_SETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CS_SETDBGLEVEL: ") ); - break; case SOUND_MIXER_PRIVATE1: CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") ); @@ -650,6 +674,8 @@ unsigned int tmp1, tmp2; unsigned int phiIncr; unsigned int correctionPerGOF, correctionPerSec; + unsigned long flags; + CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) ); /* @@ -685,11 +711,11 @@ * Fill in the SampleRateConverter control block. */ - spin_lock_irq(&state->card->lock); + spin_lock_irqsave(&state->card->lock, flags); cs461x_poke(state->card, BA1_PSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); cs461x_poke(state->card, BA1_PPI, phiIncr); - spin_unlock_irq(&state->card->lock); + spin_unlock_irqrestore(&state->card->lock, flags); dmabuf->rate = rate; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) ); @@ -704,6 +730,7 @@ unsigned int phiIncr, coeffIncr, tmp1, tmp2; unsigned int correctionPerGOF, correctionPerSec, initialDelay; unsigned int frameGroupLength, cnt; + unsigned long flags; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) ); /* @@ -766,14 +793,14 @@ /* * Fill in the VariDecimate control block. */ - spin_lock_irq(&card->lock); + spin_lock_irqsave(&card->lock, flags); cs461x_poke(card, BA1_CSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); cs461x_poke(card, BA1_CCI, coeffIncr); cs461x_poke(card, BA1_CD, (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); cs461x_poke(card, BA1_CPI, phiIncr); - spin_unlock_irq(&card->lock); + spin_unlock_irqrestore(&card->lock, flags); /* * Figure out the frame group length for the write back task. Basically, @@ -796,13 +823,13 @@ /* * Fill in the WriteBack control block. */ - spin_lock_irq(&card->lock); + spin_lock_irqsave(&card->lock, flags); cs461x_poke(card, BA1_CFG1, frameGroupLength); cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength)); cs461x_poke(card, BA1_CCST, 0x0000FFFF); cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000)); cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF); - spin_unlock_irq(&card->lock); + spin_unlock_irqrestore(&card->lock, flags); dmabuf->rate = rate; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) ); return rate; @@ -904,7 +931,7 @@ /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -static inline unsigned cs_get_dma_addr(struct cs_state *state) +extern __inline__ unsigned cs_get_dma_addr(struct cs_state *state) { struct dmabuf *dmabuf = &state->dmabuf; u32 offset; @@ -938,18 +965,20 @@ static void resync_dma_ptrs(struct cs_state *state) { - struct dmabuf *dmabuf = &state->dmabuf; - int offset; + struct dmabuf *dmabuf; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") ); - offset = 0; - dmabuf->hwptr=dmabuf->swptr = 0; - dmabuf->pringbuf = 0; + if(state) + { + dmabuf = &state->dmabuf; + dmabuf->hwptr=dmabuf->swptr = 0; + dmabuf->pringbuf = 0; + } CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") ); } /* Stop recording (lock held) */ -static inline void __stop_adc(struct cs_state *state) +extern __inline__ void __stop_adc(struct cs_state *state) { struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; @@ -983,7 +1012,9 @@ spin_lock_irqsave(&card->lock, flags); if (!(dmabuf->enable & ADC_RUNNING) && ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) - && dmabuf->ready)) + && dmabuf->ready) && + ((card->pm.flags & CS46XX_PM_IDLE) || + (card->pm.flags & CS46XX_PM_RESUMED)) ) { dmabuf->enable |= ADC_RUNNING; cs_set_divisor(dmabuf); @@ -1032,7 +1063,10 @@ CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") ); spin_lock_irqsave(&card->lock, flags); if (!(dmabuf->enable & DAC_RUNNING) && - ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready)) { + ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) && + ((card->pm.flags & CS46XX_PM_IDLE) || + (card->pm.flags & CS46XX_PM_RESUMED)) ) + { dmabuf->enable |= DAC_RUNNING; tmp = cs461x_peek(card, BA1_PCTL); tmp &= 0xFFFF; @@ -1054,54 +1088,82 @@ */ static int alloc_dmabuf(struct cs_state *state) { + + struct cs_card *card=state->card; struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf = NULL; void *tmpbuff = NULL; int order; - struct page *page, *pend; - - /* alloc as big a chunk as we can */ - for (order = defaultorder; order >= DMABUF_MINORDER; order--) - if((rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order))) - break; + struct page *map, *mapend; + unsigned long df; + + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->SGok = 0; +/* +* check for order within limits, but do not overwrite value. +*/ + if((defaultorder > 1) && (defaultorder < 12)) + df = defaultorder; + else + df = 2; - if (!rawbuf) + for (order = df; order >= DMABUF_MINORDER; order--) + if ( (rawbuf = (void *) pci_alloc_consistent( + card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr))) + break; + if (!rawbuf) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n")); return -ENOMEM; - + } dmabuf->buforder = order; dmabuf->rawbuf = rawbuf; + // Now mark the pages as reserved; otherwise the + // remap_page_range() in cs46xx_mmap doesn't work. + // 1. get index to last page in mem_map array for rawbuf. + mapend = virt_to_page(dmabuf->rawbuf + + (PAGE_SIZE << dmabuf->buforder) - 1); + + // 2. mark each physical page in range as 'reserved'. + for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) + cs4x_mem_map_reserve(map); - /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ - pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(rawbuf); page <= pend; page++) - mem_map_reserve(page); - - CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n", + CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf) ); + +/* +* only allocate the conversion buffer for the ADC +*/ + if(dmabuf->type == CS_TYPE_DAC) + { + dmabuf->tmpbuff = NULL; + dmabuf->buforder_tmpbuff = 0; + return 0; + } /* * now the temp buffer for 16/8 conversions */ - for (order = defaultorder; order >= DMABUF_MINORDER; order--) - if((tmpbuff = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order))) - break; + + tmpbuff = (void *) pci_alloc_consistent( + card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff); + if (!tmpbuff) return -ENOMEM; - CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n", + CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, tmpbuff) ); dmabuf->tmpbuff = tmpbuff; dmabuf->buforder_tmpbuff = order; - /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ - pend = virt_to_page(tmpbuff + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(tmpbuff); page <= pend; page++) - mem_map_reserve(page); - - CS_DBGOUT(CS_PARMS, 9, printk("cs461x: allocated %ld (order = %d) bytes at %p\n", - PAGE_SIZE << order, order, tmpbuff) ); - - dmabuf->ready = dmabuf->mapped = 0; - dmabuf->SGok = 0; + // Now mark the pages as reserved; otherwise the + // remap_page_range() in cs46xx_mmap doesn't work. + // 1. get index to last page in mem_map array for rawbuf. + mapend = virt_to_page(dmabuf->tmpbuff + + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); + + // 2. mark each physical page in range as 'reserved'. + for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++) + cs4x_mem_map_reserve(map); return 0; } @@ -1109,24 +1171,24 @@ static void dealloc_dmabuf(struct cs_state *state) { struct dmabuf *dmabuf = &state->dmabuf; - struct page *page, *pend; + struct page *map, *mapend; if (dmabuf->rawbuf) { - pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); - for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) - mem_map_unreserve(page); - pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, - dmabuf->rawbuf, dmabuf->dma_handle); + // Undo prog_dmabuf()'s marking the pages as reserved + mapend = virt_to_page(dmabuf->rawbuf + + (PAGE_SIZE << dmabuf->buforder) - 1); + for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) + cs4x_mem_map_unreserve(map); + free_dmabuf(state->card, dmabuf); } - dmabuf->rawbuf = NULL; if (dmabuf->tmpbuff) { - /* undo marking the pages as reserved */ - pend = virt_to_page(dmabuf->tmpbuff + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); - for (page = virt_to_page(dmabuf->tmpbuff); page <= pend; page++) - mem_map_unreserve(page); - pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder_tmpbuff, - dmabuf->tmpbuff, dmabuf->dma_handle_tmpbuff); + // Undo prog_dmabuf()'s marking the pages as reserved + mapend = virt_to_page(dmabuf->tmpbuff + + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); + for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++) + cs4x_mem_map_unreserve(map); + free_dmabuf2(state->card, dmabuf); } dmabuf->rawbuf = NULL; @@ -1197,7 +1259,7 @@ dmabuf->ready = 1; CS_DBGOUT(CS_PARMS, 4, printk( - "cs461x: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d " + "cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d " "fragsize=%d dmasize=%d\n", dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize) ); @@ -1300,7 +1362,7 @@ dmabuf->ready = 1; CS_DBGOUT(CS_PARMS, 4, printk( - "cs461x: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d " + "cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d " "fragsize=%d dmasize=%d\n", dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize) ); @@ -1358,7 +1420,7 @@ tmo += (2048*HZ)/dmabuf->rate; if (!schedule_timeout(tmo ? tmo : 1) && tmo){ - printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count); + printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count); break; } } @@ -1372,9 +1434,8 @@ /* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void cs_update_ptr(void) +static void cs_update_ptr(struct cs_card *card, int wake) { - struct cs_card *card=devs; struct cs_state *state; struct dmabuf *dmabuf; unsigned hwptr; @@ -1401,11 +1462,11 @@ if(dmabuf->mapped) { - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (wake && dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); } else { - if (dmabuf->count > 0) + if (wake && dmabuf->count > 0) wake_up(&dmabuf->wait); } } @@ -1431,7 +1492,7 @@ dmabuf->total_bytes += diff; if (dmabuf->mapped) { dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (wake && dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); /* * other drivers use fragsize, but don't see any sense @@ -1475,7 +1536,7 @@ dmabuf->count = 0; dmabuf->error++; } - if (dmabuf->count < (signed)dmabuf->dmasize/2) + if (wake && dmabuf->count < (signed)dmabuf->dmasize/2) wake_up(&dmabuf->wait); } } @@ -1544,7 +1605,7 @@ { CS_DBGOUT(CS_INTERRUPT, 8, printk( "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status)); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); } if( status & HISR_MIDI ) @@ -1681,12 +1742,26 @@ static int cs_midi_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct cs_card *card = devs; + struct cs_card *card=NULL; unsigned long flags; - while (card && card->dev_midi != minor) - card = card->next; - if (!card) - return -ENODEV; + struct list_head *entry; + + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + if (card->dev_midi == minor) + break; + } + + if (entry == &cs46xx_devs) + return -ENODEV; + if (!card) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n")); + return -ENODEV; + } + file->private_data = card; /* wait for device to become free */ down(&card->midi.open_sem); @@ -1765,13 +1840,13 @@ * Midi file operations struct. */ static /*const*/ struct file_operations cs_midi_fops = { - owner: THIS_MODULE, - llseek: cs_llseek, - read: cs_midi_read, - write: cs_midi_write, - poll: cs_midi_poll, - open: cs_midi_open, - release: cs_midi_release, + CS_OWNER CS_THIS_MODULE + llseek: cs_llseek, + read: cs_midi_read, + write: cs_midi_write, + poll: cs_midi_poll, + open: cs_midi_open, + release: cs_midi_release, }; static loff_t cs_llseek(struct file *file, loff_t offset, int origin) @@ -1806,7 +1881,7 @@ s16 *psDst=(s16 *)dst; u8 *pucDst=(u8 *)dst; - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: CopySamples()+ ") ); + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") ); CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO " dst=0x%x src=0x%x count=%d fmt=0x%x\n", (unsigned)dst,(unsigned)src,(unsigned)count,(unsigned)fmt) ); @@ -1912,14 +1987,14 @@ if (copy_to_user(dest, src, cnt)) { CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR - "cs4281: cs_copy_to_user()- fault dest=0x%x src=0x%x cnt=%d\n", + "cs46xx: cs_copy_to_user()- fault dest=0x%x src=0x%x cnt=%d\n", (unsigned)dest,(unsigned)src,cnt) ); *copied = 0; return -EFAULT; } *copied = cnt; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO - "cs4281: cs_copy_to_user()- copied bytes is %d \n",cnt) ); + "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt) ); return 0; } @@ -1927,7 +2002,7 @@ the user's buffer. it is filled by the dma machine and drained by this loop. */ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { - struct cs_card *card=devs; + struct cs_card *card = (struct cs_card *) file->private_data; struct cs_state *state; DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf; @@ -1937,7 +2012,8 @@ int cnt; unsigned copied=0; - CS_DBGOUT(CS_WAVE_READ, 4, printk("cs461x: cs_read()+ %d\n",count) ); + CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, + printk("cs46xx: cs_read()+ %d\n",count) ); state = (struct cs_state *)card->states[0]; if(!state) return -ENODEV; @@ -1951,9 +2027,18 @@ return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + ret = 0; add_wait_queue(&state->dmabuf.wait, &wait); while (count > 0) { + while(!(card->pm.flags & CS46XX_PM_IDLE)) + { + schedule(); + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + break; + } + } spin_lock_irqsave(&state->card->lock, flags); swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; @@ -1978,7 +2063,7 @@ ret = ret ? ret : -ERESTARTSYS; break; } - continue; + continue; } CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO @@ -2005,7 +2090,8 @@ } remove_wait_queue(&state->dmabuf.wait, &wait); set_current_state(TASK_RUNNING); - CS_DBGOUT(CS_WAVE_READ, 4, printk("cs461x: cs_read()- %d\n",ret) ); + CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, + printk("cs46xx: cs_read()- %d\n",ret) ); return ret; } @@ -2013,17 +2099,17 @@ the soundcard. it is drained by the dma machine and filled by this loop. */ static ssize_t cs_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { - struct cs_card *card=devs; + struct cs_card *card = (struct cs_card *) file->private_data; struct cs_state *state; DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf; - ssize_t ret = 0; + ssize_t ret; unsigned long flags; unsigned swptr; int cnt; CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4, - printk("cs461x: cs_write called, count = %d\n", count) ); + printk("cs46xx: cs_write called, count = %d\n", count) ); state = (struct cs_state *)card->states[1]; if(!state) return -ENODEV; @@ -2038,7 +2124,20 @@ if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; add_wait_queue(&state->dmabuf.wait, &wait); + ret = 0; +/* +* Start the loop to read from the user's buffer and write to the dma buffer. +* check for PM events and underrun/overrun in the loop. +*/ while (count > 0) { + while(!(card->pm.flags & CS46XX_PM_IDLE)) + { + schedule(); + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + break; + } + } spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->count < 0) { /* buffer underrun, we are recovering from sleep_on_timeout, @@ -2052,6 +2151,7 @@ dmabuf->hwptr = cs_get_dma_addr(state); dmabuf->swptr = dmabuf->hwptr; } + swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count + cnt > dmabuf->dmasize) @@ -2081,10 +2181,8 @@ if (!ret) ret = -EFAULT; return ret; } - - swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&state->card->lock, flags); + swptr = (swptr + cnt) % dmabuf->dmasize; dmabuf->swptr = swptr; dmabuf->count += cnt; if(dmabuf->count > dmabuf->dmasize) @@ -2143,7 +2241,7 @@ } spin_lock_irqsave(&card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_FALSE); if (file->f_mode & FMODE_READ) { state = card->states[0]; if(state) @@ -2170,7 +2268,8 @@ } spin_unlock_irqrestore(&card->lock, flags); - CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- \n")); + CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n", + mask)); return mask; } @@ -2184,7 +2283,7 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma) { - struct cs_card *card=devs; + struct cs_card *card = (struct cs_card *)file->private_data; struct cs_state *state; struct dmabuf *dmabuf; int ret; @@ -2199,7 +2298,7 @@ if(state) { CS_DBGOUT(CS_OPEN, 2, printk( - "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") ); + "cs46xx: cs_mmap() VM_WRITE - state CS_TRUE prog_dmabuf DAC\n") ); if ((ret = prog_dmabuf(state)) != 0) return ret; } @@ -2208,7 +2307,7 @@ if(state) { CS_DBGOUT(CS_OPEN, 2, printk( - "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") ); + "cs46xx: cs_mmap() VM_READ - state CS_TRUE prog_dmabuf ADC\n") ); if ((ret = prog_dmabuf(state)) != 0) return ret; } @@ -2231,7 +2330,7 @@ return -EINVAL; dmabuf = &state->dmabuf; - if (vma->vm_pgoff != 0) + if (cs4x_pgoff(vma) != 0) return -EINVAL; size = vma->vm_end - vma->vm_start; @@ -2617,7 +2716,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); abinfo.fragsize = dmabuf->fragsize; abinfo.fragstotal = dmabuf->numfrag; /* @@ -2640,7 +2739,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor; abinfo.bytes = dmabuf->count/dmabuf->divisor; abinfo.fragstotal = dmabuf->numfrag; @@ -2721,7 +2820,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor; cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr/dmabuf->divisor; @@ -2736,7 +2835,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); cinfo.bytes = dmabuf->total_bytes; if (dmabuf->mapped) { @@ -2772,7 +2871,7 @@ { dmabuf = &state->dmabuf; spin_lock_irqsave(&state->card->lock, flags); - cs_update_ptr(); + cs_update_ptr(card, CS_TRUE); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); } @@ -2856,10 +2955,12 @@ } } - - /* - * Untested + * For the VTB Santa Cruz card, the Secondary Codec must have the + * GPIO pins 7 and 8 manipulated, not the Primary codec. + * Currently, only the primary codec is supported, so the following + * code will not function. Additionally, slot 12 must be setup + * to allow proper output for 7 and 8 to occur (trw). */ static void amp_voyetra_4294(struct cs_card *card, int change) @@ -2897,9 +2998,9 @@ u16 control; u8 pp; unsigned long port; - int old=card->amplifier; + int old=card->active; - card->amplifier+=change; + card->active+=change; acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); if(acpi_dev == NULL) @@ -2913,24 +3014,55 @@ control=inw(port+0x10); /* Flip CLKRUN off while running */ - if(!card->amplifier && old) + if(!card->active && old) + { + CS_DBGOUT(CS_PARMS , 9, printk( + "cs46xx: clkrun() enable clkrun - change=%d active=%d\n", + change,card->active)); outw(control|0x2000, port+0x10); - else if(card->amplifier && !old) + } + else + { + /* + * sometimes on a resume the bit is set, so always reset the bit. + */ + CS_DBGOUT(CS_PARMS , 9, printk( + "cs46xx: clkrun() disable clkrun - change=%d active=%d\n", + change,card->active)); outw(control&~0x2000, port+0x10); + } } static int cs_open(struct inode *inode, struct file *file) { - struct cs_card *card = devs; + struct cs_card *card = (struct cs_card *)file->private_data; struct cs_state *state = NULL; struct dmabuf *dmabuf = NULL; + struct list_head *entry; + int minor = MINOR(inode->i_rdev); int ret=0; + unsigned int tmp; CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=0x%x %s %s\n", (unsigned)file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "", file->f_mode & FMODE_READ ? "FMODE_READ" : "") ); + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + + if (!((card->dev_audio ^ minor) & ~0xf)) + break; + } + if (entry == &cs46xx_devs) + return -ENODEV; + if (!card) { + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs46xx: cs_open(): Error - unable to find audio card struct\n")); + return -ENODEV; + } + /* * hardcode state[0] for capture, [1] for playback */ @@ -2971,6 +3103,13 @@ state->card->active_ctrl(state->card,1); state->card->amplifier_ctrl(state->card,1); + if( (tmp = cs46xx_powerup(card, CS_POWER_ADC)) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n",tmp) ); + return -EIO; + } + dmabuf->channel->state = state; /* initialize the virtual channel */ state->virt = 0; @@ -3034,6 +3173,13 @@ state->card = card; state->card->active_ctrl(state->card,1); state->card->amplifier_ctrl(state->card,1); + + if( (tmp = cs46xx_powerup(card, CS_POWER_DAC)) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n",tmp) ); + return -EIO; + } dmabuf->channel->state = state; /* initialize the virtual channel */ @@ -3074,6 +3220,7 @@ struct cs_card *card = (struct cs_card *)file->private_data; struct dmabuf *dmabuf; struct cs_state *state; + unsigned int tmp; CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=0x%x %s %s\n", (unsigned)file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "", file->f_mode & FMODE_READ ? "FMODE_READ" : "") ); @@ -3103,6 +3250,13 @@ state->card->states[state->virt] = NULL; state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC )) ) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) ); + return -EIO; + } + /* Now turn off external AMP if needed */ state->card->amplifier_ctrl(state->card, -1); state->card->active_ctrl(state->card, -1); @@ -3130,6 +3284,13 @@ state->card->states[state->virt] = NULL; state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + if( (tmp = cs461x_powerdown(card, CS_POWER_ADC )) ) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) ); + return -EIO; + } + /* Now turn off external AMP if needed */ state->card->amplifier_ctrl(state->card, -1); state->card->active_ctrl(state->card, -1); @@ -3143,127 +3304,494 @@ return 0; } -static /*const*/ struct file_operations cs461x_fops = { - owner: THIS_MODULE, - llseek: cs_llseek, - read: cs_read, - write: cs_write, - poll: cs_poll, - ioctl: cs_ioctl, - mmap: cs_mmap, - open: cs_open, - release: cs_release, -}; - -/* Write AC97 codec registers */ +void printpm(struct cs_card *s) +{ + CS_DBGOUT(CS_PM, 9, printk("pm struct:\n")); + CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n", + (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue)); + CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n", + s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue)); + CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n", + s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue)); + CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n", + s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue)); + CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n", + s->pm.u32SSCR,s->pm.u32SRCSA)); + CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n", + s->pm.u32DacASR,s->pm.u32AdcASR)); + CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n", + s->pm.u32DacSR,s->pm.u32AdcSR)); + CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n", + s->pm.u32MIDCR_Save)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n", + s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n", + s->pm.u32AC97_master_volume)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n", + s->pm.u32AC97_headphone_volume)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n", + s->pm.u32AC97_master_volume_mono)); + CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n", + s->pm.u32AC97_pcm_out_volume)); + CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n", + s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play)); + CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n", + s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture)); +} -static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg) +/**************************************************************************** +* +* Suspend - save the ac97 regs, mute the outputs and power down the part. +* +****************************************************************************/ +void cs46xx_ac97_suspend(struct cs_card *card) { - struct cs_card *card = dev->private_data; - int count; - - /* - * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address - * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 - * 3. Write ACCTL = Control Register = 460h for initiating the write - * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h - * 5. if DCV not cleared, break and return error - * 6. Read ACSTS = Status Register = 464h, check VSTS bit - */ - + int Count,i; + unsigned int tmp; + struct ac97_codec *dev=card->ac97_codec[0]; - cs461x_peekBA0(card, BA0_ACSDA); + CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n")); - /* - * Setup the AC97 control registers on the CS461x to send the - * appropriate command to the AC97 to perform the read. - * ACCAD = Command Address Register = 46Ch - * ACCDA = Command Data Register = 470h - * ACCTL = Control Register = 460h - * set DCV - will clear when process completed - * set CRW - Read command - * set VFRM - valid frame enabled - * set ESYN - ASYNC generation enabled - * set RSTN - ARST# inactive, AC97 codec not reset - */ + if(card->states[1]) + { + stop_dac(card->states[1]); + resync_dma_ptrs(card->states[1]); + } + if(card->states[0]) + { + stop_adc(card->states[0]); + resync_dma_ptrs(card->states[0]); + } - cs461x_pokeBA0(card, BA0_ACCAD, reg); - cs461x_pokeBA0(card, BA0_ACCDA, 0); - cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | - ACCTL_VFRM | ACCTL_ESYN | - ACCTL_RSTN); + for(Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) + && (i < CS46XX_AC97_NUMBER_RESTORE_REGS); + Count += 2, i++) + { + card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count); + } +/* +* Save the ac97 volume registers as well as the current powerdown state. +* Now, mute the all the outputs (master, headphone, and mono), as well +* as the PCM volume, in preparation for powering down the entire part. +*/ + card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, + (u8)BA0_AC97_MASTER_VOLUME); + card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_HEADPHONE_VOLUME); + card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_MASTER_VOLUME_MONO); + card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, + (u8)BA0_AC97_PCM_OUT_VOLUME); + + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000); + cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000); + card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL); + card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE); - /* - * Wait for the read to occur. - */ - for (count = 0; count < 500; count++) { - /* - * First, we want to wait for a short time. - */ - udelay(10); - /* - * Now, check to see if the read has completed. - * ACCTL = 460h, DCV should be reset by now and 460h = 17h - */ - if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) - break; +/* +* And power down everything on the AC97 codec. +* well, for now, only power down the DAC/ADC and MIXER VREFON components. +* trouble with removing VREF. +*/ + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) ); } - /* - * Make sure the read completed. - */ - if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) { - printk(KERN_WARNING "cs461x: AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); - return 0xffff; - } + CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_suspend()-\n")); +} - /* - * Wait for the valid status bit to go active. - */ - for (count = 0; count < 100; count++) { - /* - * Read the AC97 status register. - * ACSTS = Status Register = 464h - * VSTS - Valid Status - */ - if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS) - break; - udelay(10); - } - - /* - * Make sure we got valid status. - */ - if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)) { - printk(KERN_WARNING "cs461x: AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg); - return 0xffff; +/**************************************************************************** +* +* Resume - power up the part and restore its registers.. +* +****************************************************************************/ +void cs46xx_ac97_resume(struct cs_card *card) +{ + int Count,i; + struct ac97_codec *dev=card->ac97_codec[0]; + + CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()+\n")); + +/* +* First, we restore the state of the general purpose register. This +* contains the mic select (mic1 or mic2) and if we restore this after +* we restore the mic volume/boost state and mic2 was selected at +* suspend time, we will end up with a brief period of time where mic1 +* is selected with the volume/boost settings for mic2, causing +* acoustic feedback. So we restore the general purpose register +* first, thereby getting the correct mic selected before we restore +* the mic volume/boost. +*/ + cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE, + (u16)card->pm.u32AC97_general_purpose); + + cs_ac97_set(dev, (u8)AC97_POWER_CONTROL, + (u16)card->pm.u32AC97_powerdown); + mdelay(10); + +/* +* Now, while the outputs are still muted, restore the state of power +* on the AC97 part. +*/ + cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown); + mdelay(5); +/* +* Restore just the first set of registers, from register number +* 0x02 to the register number that ulHighestRegToRestore specifies. +*/ + for( Count = 0x2, i=0; + (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) + && (i < CS46XX_AC97_NUMBER_RESTORE_REGS); + Count += 2, i++) + { + cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]); } - /* - * Read the data returned from the AC97 register. - * ACSDA = Status Data Register = 474h - */ -#if 0 - printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg, - cs461x_peekBA0(card, BA0_ACSDA), - cs461x_peekBA0(card, BA0_ACCAD)); -#endif - return cs461x_peekBA0(card, BA0_ACSDA); + /* Check if we have to init the amplifier */ + if(card->amp_init) + card->amp_init(card); + + CS_DBGOUT(CS_PM, 9, printk("cs4281: cs46xx_ac97_resume()-\n")); } -static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) + +static int cs46xx_restart_part(struct cs_card *card) { - struct cs_card *card = dev->private_data; - int count; - int val2 = 0; - - if(reg == AC97_CD_VOL) - { - val2 = cs_ac97_get(dev, AC97_CD_VOL); - } - + struct dmabuf *dmabuf; + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk( "cs46xx: cs46xx_restart_part()+\n")); + if(card->states[1]) + { + dmabuf = &card->states[1]->dmabuf; + dmabuf->ready = 0; + resync_dma_ptrs(card->states[1]); + cs_set_divisor(dmabuf); + if(prog_dmabuf(card->states[1])) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, + printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n")); + return -1; + } + cs_set_dac_rate(card->states[1], dmabuf->rate); + } + if(card->states[0]) + { + dmabuf = &card->states[0]->dmabuf; + dmabuf->ready = 0; + resync_dma_ptrs(card->states[0]); + cs_set_divisor(dmabuf); + if(prog_dmabuf(card->states[0])) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, + printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n")); + return -1; + } + cs_set_adc_rate(card->states[0], dmabuf->rate); + } + card->pm.flags |= CS46XX_PM_RESUMED; + if(card->states[0]) + start_adc(card->states[0]); + if(card->states[1]) + start_dac(card->states[1]); + + card->pm.flags |= CS46XX_PM_IDLE; + card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED + | CS46XX_PM_RESUMING | CS46XX_PM_RESUMED); + if(card->states[0]) + wake_up(&card->states[0]->dmabuf.wait); + if(card->states[1]) + wake_up(&card->states[1]->dmabuf.wait); + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk( "cs46xx: cs46xx_restart_part()-\n")); + return 0; +} + + +static void cs461x_reset(struct cs_card *card); +static void cs461x_proc_stop(struct cs_card *card); +int cs46xx_suspend(struct cs_card *card) +{ + unsigned int tmp; + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk("cs46xx: cs46xx_suspend()+ flags=%d s=0x%x\n", + (unsigned)card->pm.flags,(unsigned)card)); +/* +* check the current state, only suspend if IDLE +*/ + if(!(card->pm.flags & CS46XX_PM_IDLE)) + { + CS_DBGOUT(CS_PM | CS_ERROR, 2, + printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n")); + return 1; + } + card->pm.flags &= ~CS46XX_PM_IDLE; + card->pm.flags |= CS46XX_PM_SUSPENDING; + + card->active_ctrl(card,1); + + tmp = cs461x_peek(card, BA1_PFIE); + tmp &= ~0x0000f03f; + tmp |= 0x00000010; + cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */ + + tmp = cs461x_peek(card, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000011; + cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */ + + /* + * Stop playback DMA. + */ + tmp = cs461x_peek(card, BA1_PCTL); + cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff); + + /* + * Stop capture DMA. + */ + tmp = cs461x_peek(card, BA1_CCTL); + cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); + + if(card->states[1]) + { + card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr; + card->pm.dmabuf_count_play = card->states[1]->dmabuf.count; + } + if(card->states[0]) + { + card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr; + card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count; + } + + cs46xx_ac97_suspend(card); + + /* + * Reset the processor. + */ + cs461x_reset(card); + + cs461x_proc_stop(card); + + /* + * Power down the DAC and ADC. For now leave the other areas on. + */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300); + + /* + * Power down the PLL. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, 0); + + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + + card->active_ctrl(card,-1); + + card->pm.flags &= ~CS46XX_PM_SUSPENDING; + card->pm.flags |= CS46XX_PM_SUSPENDED; + + printpm(card); + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk("cs46xx: cs46xx_suspend()- flags=%d\n", + (unsigned)card->pm.flags)); + return 0; +} + +int cs46xx_resume(struct cs_card *card) +{ + int i; + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, + printk( "cs46xx: cs46xx_resume()+ flags=%d\n", + (unsigned)card->pm.flags)); + if(!(card->pm.flags & CS46XX_PM_SUSPENDED)) + { + CS_DBGOUT(CS_PM | CS_ERROR, 2, + printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n")); + return 1; + } + card->pm.flags |= CS46XX_PM_RESUMING; + card->pm.flags &= ~CS46XX_PM_SUSPENDED; + printpm(card); + card->active_ctrl(card, 1); + + for(i=0;i<5;i++) + { + if (cs_hardware_init(card) != 0) + { + CS_DBGOUT(CS_PM | CS_ERROR, 4, printk( + "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n")); + mdelay(10); + cs461x_reset(card); + continue; + } + break; + } + if(i>=4) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, printk( + "cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i)); + return 0; + } + + if(cs46xx_restart_part(card)) + { + CS_DBGOUT(CS_PM | CS_ERROR, 4, printk( + "cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n")); + } + + card->active_ctrl(card, -1); + + CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=%d\n", + (unsigned)card->pm.flags)); + return 0; +} + +static /*const*/ struct file_operations cs461x_fops = { + CS_OWNER CS_THIS_MODULE + llseek: cs_llseek, + read: cs_read, + write: cs_write, + poll: cs_poll, + ioctl: cs_ioctl, + mmap: cs_mmap, + open: cs_open, + release: cs_release, +}; + +/* Write AC97 codec registers */ + + +static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct cs_card *card = dev->private_data; + int count,loopcnt; + unsigned int tmp; + + /* + * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address + * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 + * 3. Write ACCTL = Control Register = 460h for initiating the write + * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h + * 5. if DCV not cleared, break and return error + * 6. Read ACSTS = Status Register = 464h, check VSTS bit + */ + + + cs461x_peekBA0(card, BA0_ACSDA); + + /* + * Setup the AC97 control registers on the CS461x to send the + * appropriate command to the AC97 to perform the read. + * ACCAD = Command Address Register = 46Ch + * ACCDA = Command Data Register = 470h + * ACCTL = Control Register = 460h + * set DCV - will clear when process completed + * set CRW - Read command + * set VFRM - valid frame enabled + * set ESYN - ASYNC generation enabled + * set RSTN - ARST# inactive, AC97 codec not reset + */ + + cs461x_pokeBA0(card, BA0_ACCAD, reg); + cs461x_pokeBA0(card, BA0_ACCDA, 0); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | + ACCTL_VFRM | ACCTL_ESYN | + ACCTL_RSTN); + + + /* + * Wait for the read to occur. + */ + if(!(card->pm.flags & CS46XX_PM_IDLE)) + loopcnt = 2000; + else + loopcnt = 500; + for (count = 0; count < loopcnt; count++) { + /* + * First, we want to wait for a short time. + */ + udelay(10); + /* + * Now, check to see if the read has completed. + * ACCTL = 460h, DCV should be reset by now and 460h = 17h + */ + if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) + break; + } + + /* + * Make sure the read completed. + */ + if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg)); + return 0xffff; + } + + /* + * Wait for the valid status bit to go active. + */ + + if(!(card->pm.flags & CS46XX_PM_IDLE)) + loopcnt = 2000; + else + loopcnt = 100; + for (count = 0; count < loopcnt; count++) { + /* + * Read the AC97 status register. + * ACSTS = Status Register = 464h + * VSTS - Valid Status + */ + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS) + break; + udelay(10); + } + + /* + * Make sure we got valid status. + */ + if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x \n", reg, tmp)); + CS_DBGOUT(CS_ERROR, 9, printk(KERN_WARNING "returning 0xffff\n")); + return 0xffff; + } + + /* + * Read the data returned from the AC97 register. + * ACSDA = Status Data Register = 474h + */ + CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO + "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", + reg, cs461x_peekBA0(card, BA0_ACSDA), + cs461x_peekBA0(card, BA0_ACCAD))); + return (cs461x_peekBA0(card, BA0_ACSDA)); +} + +static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) +{ + struct cs_card *card = dev->private_data; + int count; + int val2 = 0; + + if(reg == AC97_CD_VOL) + { + val2 = cs_ac97_get(dev, AC97_CD_VOL); + } + /* * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 @@ -3286,6 +3814,8 @@ */ cs461x_pokeBA0(card, BA0_ACCAD, reg); cs461x_pokeBA0(card, BA0_ACCDA, val); + cs461x_peekBA0(card, BA0_ACCTL); + cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); for (count = 0; count < 1000; count++) { @@ -3304,7 +3834,10 @@ * Make sure the write completed. */ if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) - printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val); + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val)); + } /* * Adjust power if the mixer is selected/deselected according @@ -3343,7 +3876,11 @@ if(val&0x8000 || val == 0x1f1f) card->amplifier_ctrl(card, -1); else /* Mute off power on */ + { + if(card->amp_init) + card->amp_init(card); card->amplifier_ctrl(card, 1); + } } } } @@ -3355,49 +3892,87 @@ { int i=0; int minor = MINOR(inode->i_rdev); - struct cs_card *card = devs; + struct cs_card *card=NULL; + struct list_head *entry; + unsigned int tmp; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n")); - for (card = devs; card != NULL; card = card->next) + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL && card->ac97_codec[i]->dev_mixer == minor) goto match; - + } if (!card) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n")); return -ENODEV; - + } match: + if(!card->ac97_codec[i]) + return -ENODEV; file->private_data = card->ac97_codec[i]; card->active_ctrl(card,1); + if( (tmp = cs46xx_powerup(card, CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n",tmp) ); + return -EIO; + } MOD_INC_USE_COUNT; + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n")); return 0; } static int cs_release_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct cs_card *card = devs; + struct cs_card *card=NULL; + struct list_head *entry; int i; + unsigned int tmp; + - for (card = devs; card != NULL; card = card->next) + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL && card->ac97_codec[i]->dev_mixer == minor) goto match; - + } if (!card) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n")); return -ENODEV; + } match: + if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) ); + return -EIO; + } card->active_ctrl(card, -1); MOD_DEC_USE_COUNT; return 0; } +void __exit cs46xx_cleanup_module(void); static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + struct cs_card *card=NULL; + struct list_head *entry; #if CSDEBUG_INTERFACE int val; @@ -3405,7 +3980,8 @@ if( (cmd == SOUND_MIXER_CS_GETDBGMASK) || (cmd == SOUND_MIXER_CS_SETDBGMASK) || (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || - (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ) + (cmd == SOUND_MIXER_CS_SETDBGLEVEL) || + (cmd == SOUND_MIXER_CS_APM)) { switch(cmd) { @@ -3427,9 +4003,38 @@ return -EFAULT; cs_debuglevel = val; return 0; + + case SOUND_MIXER_CS_APM: + if (get_user(val, (unsigned long *) arg)) + return -EFAULT; + if(val == CS_IOCTL_CMD_SUSPEND) + { + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + cs46xx_suspend(card); + } + + } + else if(val == CS_IOCTL_CMD_RESUME) + { + list_for_each(entry, &cs46xx_devs) + { + card = list_entry(entry, struct cs_card, list); + cs46xx_resume(card); + } + } + else + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n", + val)); + } + return 0; + default: CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n") ); + "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n") ); return 0; } } @@ -3438,7 +4043,7 @@ } static /*const*/ struct file_operations cs_mixer_fops = { - owner: THIS_MODULE, + CS_OWNER CS_THIS_MODULE llseek: cs_llseek, ioctl: cs_ioctl_mixdev, open: cs_open_mixdev, @@ -3453,6 +4058,9 @@ struct ac97_codec *codec; u16 eid; + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init()+\n") ); + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -3467,13 +4075,21 @@ codec->codec_write = cs_ac97_set; if (ac97_probe_codec(codec) == 0) + { + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init()- codec number %d not found\n", + num_ac97) ); + card->ac97_codec[num_ac97] = 0; break; + } + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init() found codec %d\n",num_ac97) ); eid = cs_ac97_get(codec, AC97_EXTENDED_ID); if(eid==0xFFFFFF) { - printk(KERN_WARNING "cs461x: no codec attached ?\n"); + printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97); kfree(codec); break; } @@ -3481,17 +4097,25 @@ card->ac97_features = eid; if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) { - printk(KERN_ERR "cs461x: couldn't register mixer!\n"); + printk(KERN_ERR "cs46xx: couldn't register mixer!\n"); kfree(codec); break; } - card->ac97_codec[num_ac97] = codec; + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init() ac97_codec[%d] set to 0x%x\n", + (unsigned int)num_ac97, + (unsigned int)codec)); /* if there is no secondary codec at all, don't probe any more */ if (!ready_2nd) - return num_ac97+1; + { + num_ac97 += 1; + break; + } } + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97)); return num_ac97; } @@ -3599,96 +4223,426 @@ */ cs461x_pokeBA0(card, BA0_SERBAD, idx); /* - * Tell the serial port to load the new value into the FIFO location. + * Tell the serial port to load the new value into the FIFO location. + */ + cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC); + } + /* + * Now, if we powered up the devices, then power them back down again. + * This is kinda ugly, but should never happen. + */ + if (powerdown) + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); +} + + +static int cs461x_powerdown(struct cs_card *card, unsigned int type) +{ + int count; + unsigned int tmp=0; + + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs46xx: cs461x_powerdown()+ type=0x%x\n",type)); + if(!powerdown) + { + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs461x_powerdown() DISABLED exiting\n")); + return 0; + } + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp)); +/* +* if powering down only the VREF, and not powering down the DAC/ADC, +* then do not power down the VREF, UNLESS both the DAC and ADC are not +* currently powered down. If powering down DAC and ADC, then +* it is possible to power down the VREF (ON). +*/ + if ( ((type & CS_POWER_MIXVON) && + (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))) ) + && + ((tmp & CS_AC97_POWER_CONTROL_ADC_ON) || + (tmp & CS_AC97_POWER_CONTROL_DAC_ON) ) ) + { + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp)); + return 0; + } + /* + * Power down indicated areas. + */ + if(type & CS_POWER_MIXVOFF) + { + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n")); + /* + * Power down the MIXER (VREF ON) on the AC97 card. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) + { + tmp |= CS_AC97_POWER_CONTROL_MIXVOFF; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown MIXVOFF failed\n")); + return 1; + } + } + } + if(type & CS_POWER_MIXVON) + { + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n")); + /* + * Power down the MIXER (VREF ON) on the AC97 card. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) + { + tmp |= CS_AC97_POWER_CONTROL_MIXVON; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown MIXVON failed\n")); + return 1; + } + } + } + if(type & CS_POWER_ADC) + { + /* + * Power down the ADC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) + { + tmp |= CS_AC97_POWER_CONTROL_ADC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown ADC failed\n")); + return 1; + } + } + } + if(type & CS_POWER_DAC) + { + /* + * Power down the DAC on the AC97 card. */ - cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC); + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) + { + tmp |= CS_AC97_POWER_CONTROL_DAC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON)) + break; + } + + /* + * Check the status.. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerdown DAC failed\n")); + return 1; + } + } } - /* - * Now, if we powered up the devices, then power them back down again. - * This is kinda ugly, but should never happen. - */ - if (powerdown) - cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp)); + return 0; } -static void cs461x_powerup_dac(struct cs_card *card) +static int cs46xx_powerup(struct cs_card *card, unsigned int type) { int count; - unsigned int tmp; + unsigned int tmp=0; + CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO + "cs46xx: cs46xx_powerup()+ type=0x%x\n",type)); /* - * Power on the DACs on the AC97 card. We turn off the DAC - * powerdown bit and write the new value of the power control - * register. - */ - tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); - if (tmp & 2) /* already */ - return; - cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfdff); - + * check for VREF and powerup if need to. + */ + if(type & CS_POWER_MIXVON) + type |= CS_POWER_MIXVOFF; + if(type & (CS_POWER_DAC | CS_POWER_ADC)) + type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF; /* - * Now, we wait until we sample a DAC ready state. + * Power up indicated areas. */ - for (count = 0; count < 32; count++) { + if(type & CS_POWER_MIXVOFF) + { + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n")); /* - * First, lets wait a short while to let things settle out a - * bit, and to prevent retrying the read too quickly. + * Power up the MIXER (VREF ON) on the AC97 card. */ - udelay(50); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVOFF_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup MIXVOFF failed\n")); + return 1; + } + } + } + if(type & CS_POWER_MIXVON) + { + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n")); /* - * Read the current state of the power control register. + * Power up the MIXER (VREF ON) on the AC97 card. */ - if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2) - break; + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_MIXVON; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_MIXVON_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup MIXVON failed\n")); + return 1; + } + } } - - /* - * Check the status.. - */ - if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2)) - printk(KERN_WARNING "cs461x: powerup DAC failed\n"); -} + if(type & CS_POWER_ADC) + { + /* + * Power up the ADC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_ADC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); -static void cs461x_powerup_adc(struct cs_card *card) -{ - int count; - unsigned int tmp; + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); - /* - * Power on the ADCs on the AC97 card. We turn off the DAC - * powerdown bit and write the new value of the power control - * register. - */ - tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); - if (tmp & 1) /* already */ - return; - cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfeff); + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON) + break; + } - /* - * Now, we wait until we sample a ADC ready state. - */ - for (count = 0; count < 32; count++) { + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_ADC_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup ADC failed\n")); + return 1; + } + } + } + if(type & CS_POWER_DAC) + { /* - * First, lets wait a short while to let things settle out a - * bit, and to prevent retrying the read too quickly. + * Power up the DAC on the AC97 card. */ - udelay(50); - /* - * Read the current state of the power control register. - */ - if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1) - break; - } + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n")); + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) + { + tmp &= ~CS_AC97_POWER_CONTROL_DAC; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); - /* - * Check the status.. - */ - if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1)) - printk(KERN_WARNING "cs461x: powerup ADC failed\n"); + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + CS_AC97_POWER_CONTROL_DAC_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "cs46xx: powerup DAC failed\n")); + return 1; + } + } + } + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO + "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp)); + return 0; } + static void cs461x_proc_start(struct cs_card *card) { int cnt; @@ -3713,7 +4667,7 @@ } if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR) - printk(KERN_WARNING "cs461x: SPCR_RUNFR never reset\n"); + printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n"); } static void cs461x_proc_stop(struct cs_card *card) @@ -3725,13 +4679,13 @@ cs461x_poke(card, BA1_SPCR, 0); } - - static int cs_hardware_init(struct cs_card *card) { unsigned long end_time; - unsigned int tmp; + unsigned int tmp,count; + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_hardware_init()+\n") ); /* * First, blast the clock control register to zero so that the PLL starts * out in a known state, and blast the master serial port control register @@ -3753,6 +4707,8 @@ * there might be logic external to the CS461x that uses the ARST# line * for a reset. */ + cs461x_pokeBA0(card, BA0_ACCTL, 1); + udelay(50); cs461x_pokeBA0(card, BA0_ACCTL, 0); udelay(50); cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN); @@ -3778,6 +4734,15 @@ cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97); /* + * The part seems to not be ready for a while after a resume. + * so, if we are resuming, then wait for 700 mils. Note that 600 mils + * is not enough for some platforms! tested on an IBM Thinkpads and + * reference cards. + */ + if(!(card->pm.flags & CS46XX_PM_IDLE)) + mdelay(initdelay); + + /* * Write the selected clock control setup to the hardware. Do not turn on * SWCE yet (if requested), so that the devices clocked by the output of * PLL are not clocked until the PLL is stable. @@ -3823,27 +4788,48 @@ mdelay(5); /* Shouldnt be needed ?? */ +/* +* If we are resuming under 2.2.x then we can not schedule a timeout. +* so, just spin the CPU. +*/ + if(card->pm.flags & CS46XX_PM_IDLE) + { /* * Wait for the card ready signal from the AC97 card. */ - end_time = jiffies + 3 * (HZ >> 2); - do { + end_time = jiffies + 3 * (HZ >> 2); + do { /* * Read the AC97 status register to see if we've seen a CODEC READY * signal from the AC97 card. */ - if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) - break; - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1); - } while (time_before(jiffies, end_time)); + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + } + else + { + for (count = 0; count < 100; count++) { + // First, we want to wait for a short time. + udelay(25); + + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) + break; + } + } /* * Make sure CODEC is READY. */ if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) { - printk(KERN_WARNING "cs461x: create - never read card ready from AC'97\n"); - printk(KERN_WARNING "cs461x: it is probably not a bug, try using the CS4232 driver\n"); + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING + "cs46xx: create - never read card ready from AC'97\n")); + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING + "cs46xx: probably not a bug, try using the CS4232 driver,\n")); + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING + "cs46xx: or turn off any automatic Power Management support in the BIOS.\n")); return -EIO; } @@ -3853,28 +4839,40 @@ */ cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); + if(card->pm.flags & CS46XX_PM_IDLE) + { /* * Wait until we've sampled input slots 3 and 4 as valid, meaning that * the card is pumping ADC data across the AC-link. */ - end_time = jiffies + 3 * (HZ >> 2); - do { - /* - * Read the input slot valid register and see if input slots 3 and - * 4 are valid yet. - */ - if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) - break; - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1); - } while (time_before(jiffies, end_time)); + end_time = jiffies + 3 * (HZ >> 2); + do { + /* + * Read the input slot valid register and see if input slots 3 and + * 4 are valid yet. + */ + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + } + else + { + for (count = 0; count < 100; count++) { + // First, we want to wait for a short time. + udelay(25); + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) + break; + } + } /* * Make sure input slots 3 and 4 are valid. If not, then return * an error. */ if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) { - printk(KERN_WARNING "cs461x: create - never read ISV3 & ISV4 from AC'97\n"); + printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n"); return -EIO; } @@ -3885,12 +4883,6 @@ cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4); /* - * Power down the DAC and ADC. We will power them up (if) when we need - * them. - */ - /* cs461x_pokeBA0(card, BA0_AC97_POWERDOWN, 0x300); */ - - /* * Turn off the Processor by turning off the software clock enable flag in * the clock control register. */ @@ -3923,14 +4915,20 @@ cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); /* initialize AC97 codec and register /dev/mixer */ - if (cs_ac97_init(card) <= 0) - return -EIO; - - mdelay(5); /* Do we need this ?? */ + if(card->pm.flags & CS46XX_PM_IDLE) + { + if (cs_ac97_init(card) <= 0) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs_ac97_init() failure\n") ); + return -EIO; + } + } + else + { + cs46xx_ac97_resume(card); + } - cs461x_powerup_adc(card); - cs461x_powerup_dac(card); - cs461x_proc_start(card); /* @@ -3946,11 +4944,29 @@ tmp &= ~0x0000003f; tmp |= 0x00000001; cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */ + + /* + * If IDLE then Power down the part. We will power components up + * when we need them. + */ + if(card->pm.flags & CS46XX_PM_IDLE) + { + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) ); + return -EIO; + } + } + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "cs46xx: cs_hardware_init()- 0\n")); return 0; } + /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ /* @@ -3963,65 +4979,77 @@ u16 id; char *name; void (*amp)(struct cs_card *, int); + void (*amp_init)(struct cs_card *); void (*active)(struct cs_card *, int); }; -static struct cs_card_type __initdata cards[]={ - {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL}, - {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL}, - {0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL}, +static struct cs_card_type cards[]={ + {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL}, + {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL, NULL}, + {0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL}, + {0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL}, + {0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL}, /* Not sure if the 570 needs the clkrun hack */ - {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack}, - {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack}, - {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL}, - {0, 0, "Card without SSID set", NULL, NULL }, + {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, NULL, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL, NULL}, + {0, 0, "Card without SSID set", NULL, NULL, NULL }, {0, 0, NULL, NULL, NULL} }; -#ifdef CS46XX_PM -static int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ -struct cs_state *state = (struct cs_state *) dev->data; - - if (state) { - switch(rqst) { - case PM_RESUME: - printk( KERN_DEBUG "cs46xx: PM resume request\n"); - cs_hardware_init(state->card); - break; - case PM_SUSPEND: - printk( KERN_DEBUG "cs46xx: PM suspend request\n"); - stop_dac(state); - resync_dma_ptrs(state); - break; - } - } +MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>"); +MODULE_DESCRIPTION("Crystal SoundFusion Audio Support"); -return 0; -} -#endif +static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n"; +static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n"; -static int __init cs_install(struct pci_dev *pci_dev) +static int __devinit cs46xx_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pciid) { - struct cs_card *card; - struct cs_card_type *cp = &cards[0]; -#ifdef CS46XX_PM struct pm_dev *pmdev; -#endif + int i,j; u16 ss_card, ss_vendor; - - + struct cs_card *card; + dma_addr_t dma_mask; + struct cs_card_type *cp = &cards[0]; + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, + printk(KERN_INFO "cs46xx: probe()+\n")); + + if (!RSRCISMEMORYREGION(pci_dev, 0) || + !RSRCISMEMORYREGION(pci_dev, 1)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: probe()- Memory region not assigned\n")); + return -1; + } + if (pci_dev->irq == 0) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: probe() IRQ not assigned\n")); + return -1; + } + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n")); + return -1; + } + dma_mask = 0xffffffff; /* this enables playback and recording */ + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor); pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card); if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "cs461x: out of memory\n"); + printk(KERN_ERR "cs46xx: out of memory\n"); return -ENOMEM; } memset(card, 0, sizeof(*card)); - card->ba0_addr = pci_resource_start(pci_dev, 0); - card->ba1_addr = pci_resource_start(pci_dev, 1); + if (pci_enable_device(pci_dev)) { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR + "cs46xx: pci_enable_device() failed\n")); + goto fail2; + } + card->ba0_addr = RSRCADDRESS(pci_dev, 0); + card->ba1_addr = RSRCADDRESS(pci_dev, 1); card->pci_dev = pci_dev; card->irq = pci_dev->irq; card->magic = CS_CARD_MAGIC; @@ -4029,7 +5057,8 @@ pci_set_master(pci_dev); - printk(KERN_INFO "cs461x: Card found at 0x%08lx and 0x%08lx, IRQ %d\n", + printk(cs46xx_banner); + printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n", card->ba0_addr, card->ba1_addr, card->irq); card->alloc_pcm_channel = cs_alloc_pcm_channel; @@ -4037,7 +5066,7 @@ card->free_pcm_channel = cs_free_pcm_channel; card->amplifier_ctrl = amp_none; card->active_ctrl = amp_none; - + while (cp->name) { if(cp->vendor == ss_vendor && cp->id == ss_card) @@ -4045,19 +5074,21 @@ card->amplifier_ctrl = cp->amp; if(cp->active) card->active_ctrl = cp->active; + if(cp->amp_init) + card->amp_init = cp->amp_init; break; } cp++; } if (cp->name==NULL) { - printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", + printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq); } else { - printk(KERN_INFO "cs461x: %s at 0x%08lx/0x%08lx, IRQ %d\n", - cp->name, card->ba0_addr, card->ba1_addr, card->irq); + printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", + cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq); } if (card->amplifier_ctrl==NULL) @@ -4068,74 +5099,121 @@ if (external_amp == 1) { - printk(KERN_INFO "cs461x: Crystal EAPD support forced on.\n"); + printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n"); card->amplifier_ctrl = amp_voyetra; } if (thinkpad == 1) { + printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n"); card->active_ctrl = clkrun_hack; - printk(KERN_INFO "cs461x: Activating CLKRUN hack for Thinkpad.\n"); } card->active_ctrl(card, 1); - + /* claim our iospace and irq */ - card->ba0 = ioremap(card->ba0_addr, CS461X_BA0_SIZE); - card->ba1.name.data0 = ioremap(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); - card->ba1.name.data1 = ioremap(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); - card->ba1.name.pmem = ioremap(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); - card->ba1.name.reg = ioremap(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); - - CS_DBGOUT(CS_INIT, 4, printk("card->ba0=0x%.08x\n",(unsigned)card->ba0) ); - CS_DBGOUT(CS_INIT, 4, printk("card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n", - (unsigned)card->ba1.name.data0, - (unsigned)card->ba1.name.data1, - (unsigned)card->ba1.name.pmem, - (unsigned)card->ba1.name.reg) ); + card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE); + card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); + card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); + card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); + card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); + + CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO + "cs46xx: card->ba0=0x%.08x\n",(unsigned)card->ba0) ); + CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO + "cs46xx: card->ba1=0x%.08x 0x%.08x 0x%.08x 0x%.08x\n", + (unsigned)card->ba1.name.data0, + (unsigned)card->ba1.name.data1, + (unsigned)card->ba1.name.pmem, + (unsigned)card->ba1.name.reg) ); if(card->ba0 == 0 || card->ba1.name.data0 == 0 || card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 || card->ba1.name.reg == 0) goto fail2; - if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs461x", card)) { - printk(KERN_ERR "cs461x: unable to allocate irq %d\n", card->irq); + if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs46xx", card)) { + printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq); goto fail2; } /* register /dev/dsp */ if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) { - printk(KERN_ERR "cs461x: unable to register dsp\n"); + printk(KERN_ERR "cs46xx: unable to register dsp\n"); goto fail; } /* register /dev/midi */ if((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0) - printk(KERN_ERR "cs461x: unable to register midi\n"); + printk(KERN_ERR "cs46xx: unable to register midi\n"); - if (cs_hardware_init(card)<0) - { + card->pm.flags |= CS46XX_PM_IDLE; + for(i=0;i<5;i++) + { + if (cs_hardware_init(card) != 0) + { + CS_DBGOUT(CS_ERROR, 4, printk( + "cs46xx: ERROR in cs_hardware_init()... retrying\n")); + for (j = 0; j < NR_AC97; j++) + if (card->ac97_codec[j] != NULL) { + unregister_sound_mixer(card->ac97_codec[j]->dev_mixer); + kfree (card->ac97_codec[j]); + } + mdelay(10); + continue; + } + break; + } + if(i>=4) + { + CS_DBGOUT(CS_PM | CS_ERROR, 1, printk( + "cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i)); unregister_sound_dsp(card->dev_audio); if(card->dev_midi) unregister_sound_midi(card->dev_midi); goto fail; - } + } + init_waitqueue_head(&card->midi.open_wait); init_MUTEX(&card->midi.open_sem); init_waitqueue_head(&card->midi.iwait); init_waitqueue_head(&card->midi.owait); - card->next = devs; - devs = card; cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST); cs461x_pokeBA0(card, BA0_MIDCR, 0); - + + /* + * Check if we have to init the amplifier, but probably already done + * since the CD logic in the ac97 init code will turn on the ext amp. + */ + if(cp->amp_init) + cp->amp_init(card); card->active_ctrl(card, -1); -#ifdef CS46XX_PM - pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), cs46xx_pm_callback); - if (pmdev) - pmdev->data = card; -#endif + + PCI_SET_DRIVER_DATA(pci_dev, card); + PCI_SET_DMA_MASK(pci_dev, dma_mask); + list_add(&card->list, &cs46xx_devs); + + pmdev = cs_pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), cs46xx_pm_callback); + if (pmdev) + { + CS_DBGOUT(CS_INIT | CS_PM, 4, printk(KERN_INFO + "cs46xx: probe() pm_register() succeeded (0x%x).\n", + (unsigned)pmdev)); + pmdev->data = card; + } + else + { + CS_DBGOUT(CS_INIT | CS_PM | CS_ERROR, 2, printk(KERN_INFO + "cs46xx: probe() pm_register() failed (0x%x).\n", + (unsigned)pmdev)); + card->pm.flags |= CS46XX_PM_NOT_REGISTERED; + } + + CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=0x%x\n", + (unsigned)card->pm.flags,(unsigned)card)); + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: probe()- device allocated successfully\n")); return 0; fail: @@ -4152,15 +5230,22 @@ if(card->ba1.name.reg) iounmap(card->ba1.name.reg); kfree(card); + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO + "cs46xx: probe()- no device allocated\n")); return -ENODEV; +} // probe_cs46xx -} +// --------------------------------------------------------------------- -static void cs_remove(struct cs_card *card) +static void __devinit cs46xx_remove(struct pci_dev *pci_dev) { + struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev); int i; unsigned int tmp; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_remove()+\n")); + card->active_ctrl(card,1); tmp = cs461x_peek(card, BA1_PFIE); @@ -4196,7 +5281,12 @@ * Power down the DAC and ADC. We will power them up (if) when we need * them. */ - cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x300); + if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC | + CS_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) ); + } /* * Power down the PLL. @@ -4230,54 +5320,123 @@ if(card->dev_midi) unregister_sound_midi(card->dev_midi); kfree(card); -} + PCI_SET_DRIVER_DATA(pci_dev,NULL); + list_del(&card->list); -MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <audio@crystal.cirrus.com>"); -MODULE_DESCRIPTION("Crystal SoundFusion Audio Support"); + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_remove()-: remove successful\n")); +} -static char banner[] __initdata = KERN_INFO "Crystal 4280/461x + AC97 Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"; -static char fndmsg[] __initdata = KERN_INFO "cs461x: Found %d audio device(s).\n"; +enum { + CS46XX_4610 = 0, + CS46XX_4612, /* same as 4624 */ + CS46XX_4615, /* same as 4630 */ +}; -static int __init cs_init_driver(void) -{ - struct pci_dev *pcidev = NULL; - int foundone=0; +static struct pci_device_id cs46xx_pci_tbl[] __devinitdata = { + + {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4610}, + {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4612}, + {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_4615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CS46XX_4615}, + {0,} +}; - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; +MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl); - printk(banner); +struct pci_driver cs46xx_pci_driver = { + name:"cs46xx", + id_table:cs46xx_pci_tbl, + probe:cs46xx_probe, + remove:cs46xx_remove, + suspend:CS46XX_SUSPEND_TBL, + resume:CS46XX_RESUME_TBL, +}; - while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) { - if (cs_install(pcidev)==0) - foundone++; - } - while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) { - if (cs_install(pcidev)==0) - foundone++; +int __init cs46xx_init_module(void) +{ + int rtn = 0; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_init_module()+ \n")); + if (!pci_present()) { /* No PCI bus in this machine! */ + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "cs46xx: cs46xx_init_module()- no pci bus found\n")); + return -ENODEV; } - while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) { - if (cs_install(pcidev)==0) - foundone++; + rtn = pci_module_init(&cs46xx_pci_driver); + + if(rtn == -ENODEV) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk( + "cs46xx: Unable to detect valid cs46xx device\n")); } - printk(fndmsg, foundone); - return foundone ? 0 : -ENODEV; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn)); + return rtn; } -static void __exit cs_exit_driver(void) +void __exit cs46xx_cleanup_module(void) { - struct cs_card *next; -#ifdef CS46XX_PM - pm_unregister_all(cs46xx_pm_callback); -#endif - while(devs) - { - next=devs->next; - cs_remove(devs); - devs=next; + pci_unregister_driver(&cs46xx_pci_driver); + cs_pm_unregister_all(cs46xx_pm_callback); + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n")); +} + +module_init(cs46xx_init_module); +module_exit(cs46xx_cleanup_module); + +int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct cs_card *card; + + CS_DBGOUT(CS_PM, 2, printk(KERN_INFO + "cs46xx: cs46xx_pm_callback dev=0x%x rqst=0x%x card=%d\n", + (unsigned)dev,(unsigned)rqst,(unsigned)data)); + card = (struct cs_card *) dev->data; + if (card) { + switch(rqst) { + case PM_SUSPEND: + CS_DBGOUT(CS_PM, 2, printk(KERN_INFO + "cs46xx: PM suspend request\n")); + if(cs46xx_suspend(card)) + { + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO + "cs46xx: PM suspend request refused\n")); + return 1; + } + break; + case PM_RESUME: + CS_DBGOUT(CS_PM, 2, printk(KERN_INFO + "cs46xx: PM resume request\n")); + if(cs46xx_resume(card)) + { + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO + "cs46xx: PM resume request refused\n")); + return 1; + } + break; + } } + + return 0; +} + +static void cs46xx_suspend_tbl(struct pci_dev *pcidev) +{ + struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev); + CS_DBGOUT(CS_PM | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n")); + cs46xx_suspend(s); + return; +} + +static void cs46xx_resume_tbl(struct pci_dev *pcidev) +{ + struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev); + CS_DBGOUT(CS_PM | CS_FUNCTION, 2, + printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n")); + cs46xx_resume(s); + return; } -module_init(cs_init_driver); -module_exit(cs_exit_driver); diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xx_wrapper-24.h linux/drivers/sound/cs46xx_wrapper-24.h --- v2.4.3/linux/drivers/sound/cs46xx_wrapper-24.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs46xx_wrapper-24.h Wed Apr 11 19:02:38 2001 @@ -0,0 +1,56 @@ +/******************************************************************************* +* +* "cs46xx_wrapper.c" -- Cirrus Logic-Crystal CS46XX linux audio driver. +* +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- tom woller (twoller@crystal.cirrus.com) or +* (pcaudio@crystal.cirrus.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 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. +* +* 01/11/2001 trw - new file from cs4281 wrapper code. +* +*******************************************************************************/ +#ifndef __CS46XX_WRAPPER24_H +#define __CS46XX_WRAPPER24_H + +#include <linux/spinlock.h> + +#define CS_OWNER owner: +#define CS_THIS_MODULE THIS_MODULE, +void cs46xx_null(struct pci_dev *pcidev) { return; } +#define cs4x_mem_map_reserve(page) mem_map_reserve(page) +#define cs4x_mem_map_unreserve(page) mem_map_unreserve(page) + +#define free_dmabuf(card, dmabuf) \ + pci_free_consistent((card)->pci_dev, \ + PAGE_SIZE << (dmabuf)->buforder, \ + (dmabuf)->rawbuf, (dmabuf)->dmaaddr); +#define free_dmabuf2(card, dmabuf) \ + pci_free_consistent((card)->pci_dev, \ + PAGE_SIZE << (dmabuf)->buforder_tmpbuff, \ + (dmabuf)->tmpbuff, (dmabuf)->dmaaddr_tmpbuff); +#define cs4x_pgoff(vma) ((vma)->vm_pgoff) + +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#define PCI_GET_DRIVER_DATA pci_get_drvdata +#define PCI_SET_DRIVER_DATA pci_set_drvdata +#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask + +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xxpm-24.h linux/drivers/sound/cs46xxpm-24.h --- v2.4.3/linux/drivers/sound/cs46xxpm-24.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs46xxpm-24.h Wed Apr 11 19:02:38 2001 @@ -0,0 +1,53 @@ +/******************************************************************************* +* +* "cs46xxpm-24.h" -- Cirrus Logic-Crystal CS46XX linux audio driver. +* +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- tom woller (twoller@crystal.cirrus.com) or +* (pcaudio@crystal.cirrus.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 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. +* +* 12/22/00 trw - new file. +* +*******************************************************************************/ +#ifndef __CS46XXPM24_H +#define __CS46XXPM24_H + +#include <linux/pm.h> +#include "cs46xxpm.h" + + +#define CS46XX_ACPI_SUPPORT 1 +#ifdef CS46XX_ACPI_SUPPORT +/* +* for now (12/22/00) only enable the pm_register PM support. +* allow these table entries to be null. +*/ +static void cs46xx_suspend_tbl(struct pci_dev *pcidev); +static void cs46xx_resume_tbl(struct pci_dev *pcidev); +#define cs_pm_register(a, b, c) 0 +#define cs_pm_unregister_all(a) +#define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl +#define CS46XX_RESUME_TBL cs46xx_resume_tbl +#else +#define cs_pm_register(a, b, c) pm_register((a), (b), (c)); +#define cs_pm_unregister_all(a) pm_unregister_all((a)); +#define CS46XX_SUSPEND_TBL cs46xx_null +#define CS46XX_RESUME_TBL cs46xx_null +#endif +int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data); + +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/sound/cs46xxpm.h linux/drivers/sound/cs46xxpm.h --- v2.4.3/linux/drivers/sound/cs46xxpm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs46xxpm.h Wed Apr 11 19:02:38 2001 @@ -0,0 +1,70 @@ +/******************************************************************************* +* +* "cs46xxpm.h" -- Cirrus Logic-Crystal CS46XX linux audio driver. +* +* Copyright (C) 2000,2001 Cirrus Logic Corp. +* -- tom woller (twoller@crystal.cirrus.com) or +* (pcaudio@crystal.cirrus.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 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. +* +* 12/22/00 trw - new file. +* +*******************************************************************************/ +#ifndef __CS46XXPM_H +#define __CS46XXPM_H + +#define CS46XX_AC97_HIGHESTREGTORESTORE 0x26 +#define CS46XX_AC97_NUMBER_RESTORE_REGS (CS46XX_AC97_HIGHESTREGTORESTORE/2-1) + +/* PM state defintions */ +#define CS46XX_PM_NOT_REGISTERED 0x1000 +#define CS46XX_PM_IDLE 0x0001 +#define CS46XX_PM_SUSPENDING 0x0002 +#define CS46XX_PM_SUSPENDED 0x0004 +#define CS46XX_PM_RESUMING 0x0008 +#define CS46XX_PM_RESUMED 0x0010 + +#define CS_POWER_DAC 0x0001 +#define CS_POWER_ADC 0x0002 +#define CS_POWER_MIXVON 0x0004 +#define CS_POWER_MIXVOFF 0x0008 +#define CS_AC97_POWER_CONTROL_ON 0xf000 /* always on bits (inverted) */ +#define CS_AC97_POWER_CONTROL_ADC 0x0100 +#define CS_AC97_POWER_CONTROL_DAC 0x0200 +#define CS_AC97_POWER_CONTROL_MIXVON 0x0400 +#define CS_AC97_POWER_CONTROL_MIXVOFF 0x0800 +#define CS_AC97_POWER_CONTROL_ADC_ON 0x0001 +#define CS_AC97_POWER_CONTROL_DAC_ON 0x0002 +#define CS_AC97_POWER_CONTROL_MIXVON_ON 0x0004 +#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008 + +struct cs46xx_pm { + unsigned long flags; + u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue; + u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR; + u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save; + u32 u32SSPM_BITS; + u32 ac97[CS46XX_AC97_NUMBER_RESTORE_REGS]; + u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono; + u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose; + u32 u32hwptr_playback,u32hwptr_capture; + unsigned dmabuf_swptr_play; + int dmabuf_count_play; + unsigned dmabuf_swptr_capture; + int dmabuf_count_capture; +}; + +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/sound/emu10k1/cardmi.h linux/drivers/sound/emu10k1/cardmi.h --- v2.4.3/linux/drivers/sound/emu10k1/cardmi.h Mon Dec 11 13:02:20 2000 +++ linux/drivers/sound/emu10k1/cardmi.h Fri Apr 13 20:26:07 2001 @@ -34,6 +34,7 @@ #define _CARDMI_H #include "icardmid.h" +#include <linux/sched.h> #include <linux/interrupt.h> typedef enum diff -u --recursive --new-file v2.4.3/linux/drivers/sound/emu10k1/timer.h linux/drivers/sound/emu10k1/timer.h --- v2.4.3/linux/drivers/sound/emu10k1/timer.h Mon Dec 11 13:02:19 2000 +++ linux/drivers/sound/emu10k1/timer.h Fri Apr 13 20:26:07 2001 @@ -27,6 +27,7 @@ #ifndef _TIMER_H #define _TIMER_H +#include <linux/sched.h> #include <linux/interrupt.h> #include "hwaccess.h" diff -u --recursive --new-file v2.4.3/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.3/linux/drivers/sound/es1370.c Tue Mar 20 12:04:58 2001 +++ linux/drivers/sound/es1370.c Thu Apr 12 12:16:36 2001 @@ -3,7 +3,7 @@ /* * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -117,6 +117,11 @@ * Tim Janik's BSE (Bedevilled Sound Engine) found this * 07.02.2000 0.33 Use pci_alloc_consistent and pci_register_driver * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.35 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 07.01.2001 0.36 Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de> + * 31.01.2001 0.37 Register/Unregister gameport + * Fix SETTRIGGER non OSS API conformity * * some important things missing in Ensoniq documentation: * @@ -159,6 +164,23 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -170,6 +192,7 @@ #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif + #ifndef PCI_DEVICE_ID_ENSONIQ_ES1370 #define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 #endif @@ -361,6 +384,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -375,6 +399,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -419,15 +445,16 @@ static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data) { - unsigned long tmo = jiffies + HZ/10; + unsigned long tmo = jiffies + HZ/10, j; do { + j = jiffies; if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) { outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC); return; } schedule(); - } while ((signed)(tmo-jiffies) > 0); + } while ((signed)(tmo-j) > 0); printk(KERN_ERR "es1370: write to codec register timeout\n"); } @@ -600,6 +627,7 @@ outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE); outl(db->dmaaddr, s->io+(reg & 0xff)); outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); + db->enabled = 1; db->ready = 1; return 0; } @@ -1168,7 +1196,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1195,7 +1224,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); @@ -1238,7 +1268,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1266,7 +1297,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -1520,25 +1552,31 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; + s->dma_adc.enabled = 1; start_adc(s); - } else + } else { + s->dma_adc.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) return ret; + s->dma_dac2.enabled = 1; start_dac2(s); - } else + } else { + s->dma_dac2.enabled = 0; stop_dac2(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; @@ -1554,8 +1592,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1575,8 +1613,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); count = s->dma_dac2.count; @@ -1588,8 +1626,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1606,8 +1644,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; @@ -1729,6 +1767,7 @@ s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; s->sctrl &= ~SCTRL_R1FMT; if ((minor & 0xf) == SND_DEV_DSP16) s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT; @@ -1737,6 +1776,7 @@ } if (file->f_mode & FMODE_WRITE) { s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; + s->dma_dac2.enabled = 1; s->sctrl &= ~SCTRL_P2FMT; if ((minor & 0xf) == SND_DEV_DSP16) s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT; @@ -1772,8 +1812,8 @@ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); - return 0; unlock_kernel(); + return 0; } static /*const*/ struct file_operations es1370_audio_fops = { @@ -1825,7 +1865,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1853,7 +1894,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -2021,13 +2063,16 @@ if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; + s->dma_dac1.enabled = 1; start_dac1(s); - } else + } else { + s->dma_dac1.enabled = 0; stop_dac1(s); + } return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); @@ -2046,6 +2091,8 @@ return 0; case SNDCTL_DSP_GETODELAY: + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); count = s->dma_dac1.count; @@ -2055,8 +2102,8 @@ return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; @@ -2158,6 +2205,7 @@ down(&s->open_sem); } s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; + s->dma_dac1.enabled = 1; spin_lock_irqsave(&s->lock, flags); s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL); s->sctrl &= ~SCTRL_P1FMT; @@ -2439,6 +2487,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2560,11 +2609,16 @@ /* note: setting CTRL_SERR_DIS is reported to break * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); + s->gameport.io = 0; + s->gameport.size = 0; if (joystick[devindex]) { - if (check_region(0x200, JOY_EXTENT)) - printk(KERN_ERR "es1370: io port 0x200 in use\n"); - else + if (!request_region(0x200, JOY_EXTENT, "es1370")) + printk(KERN_ERR "es1370: joystick io port 0x200 in use\n"); + else { s->ctrl |= CTRL_JYSTK_EN; + s->gameport.io = 0x200; + s->gameport.size = JOY_EXTENT; + } } if (lineout[devindex]) s->ctrl |= CTRL_XCTL0; @@ -2607,6 +2661,9 @@ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); } set_fs(fs); + /* register gameport */ + gameport_register_port(&s->gameport); + /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ @@ -2625,6 +2682,8 @@ err_dev1: printk(KERN_ERR "es1370: cannot register misc device\n"); free_irq(s->irq, s); + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); err_irq: release_region(s->io, ES1370_EXTENT); err_region: @@ -2634,22 +2693,26 @@ static void __devinit es1370_remove(struct pci_dev *dev) { - struct es1370_state *s = pci_get_drvdata(dev); + struct es1370_state *s = pci_get_drvdata(dev); - if (!s) - return; - list_del(&s->devs); - outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(); - free_irq(s->irq, s); - release_region(s->io, ES1370_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - kfree(s); - pci_set_drvdata(dev, NULL); + if (!s) + return; + list_del(&s->devs); + outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ + outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ + synchronize_irq(); + free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } + release_region(s->io, ES1370_EXTENT); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_dsp(s->dev_dac); + unregister_sound_midi(s->dev_midi); + kfree(s); + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { @@ -2670,7 +2733,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.34 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.37 time " __TIME__ " " __DATE__ "\n"); return pci_module_init(&es1370_driver); } diff -u --recursive --new-file v2.4.3/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.3/linux/drivers/sound/es1371.c Tue Mar 20 12:04:58 2001 +++ linux/drivers/sound/es1371.c Thu Apr 12 12:16:36 2001 @@ -3,7 +3,7 @@ /* * es1371.c -- Creative Ensoniq ES1371. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -102,6 +102,13 @@ * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com> * Use pci_module_init * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.28 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 05.01.2001 0.29 Hopefully updates will not be required anymore when Creative bumps + * the CT5880 revision. + * suggested by Stephan Müller <smueller@chronox.de> + * 31.01.2001 0.30 Register/Unregister gameport + * Fix SETTRIGGER non OSS API conformity */ /*****************************************************************************/ @@ -129,6 +136,23 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -168,6 +192,7 @@ #define ES1371REV_ES1373_B 0x06 #define ES1371REV_CT5880_A 0x07 #define CT5880REV_CT5880_C 0x02 +#define CT5880REV_CT5880_D 0x03 #define ES1371REV_ES1371_B 0x09 #define EV1938REV_EV1938_A 0x00 #define ES1371REV_ES1373_8 0x08 @@ -432,6 +457,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -446,6 +472,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -932,6 +960,7 @@ outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); outl(db->dmaaddr, s->io+(reg & 0xff)); outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); + db->enabled = 1; db->ready = 1; return 0; } @@ -1351,7 +1380,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1378,7 +1408,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); @@ -1421,7 +1452,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1449,7 +1481,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac2(s); + if (s->dma_dac2.enabled) + start_dac2(s); } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -1700,25 +1733,31 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; + s->dma_adc.enabled = 1; start_adc(s); - } else + } else { + s->dma_adc.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) return ret; + s->dma_dac2.enabled = 1; start_dac2(s); - } else + } else { + s->dma_dac2.enabled = 0; stop_dac2(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; @@ -1734,8 +1773,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1755,8 +1794,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); count = s->dma_dac2.count; @@ -1768,8 +1807,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1786,8 +1825,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; @@ -1904,10 +1943,12 @@ } if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; set_adc_rate(s, 8000); } if (file->f_mode & FMODE_WRITE) { s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; + s->dma_dac2.enabled = 1; set_dac2_rate(s, 8000); } spin_lock_irqsave(&s->lock, flags); @@ -2005,7 +2046,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -2033,7 +2075,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac1(s); + if (s->dma_dac1.enabled) + start_dac1(s); } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -2192,13 +2235,16 @@ if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; + s->dma_dac1.enabled = 1; start_dac1(s); - } else + } else { + s->dma_dac1.enabled = 0; stop_dac1(s); + } return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); @@ -2217,6 +2263,8 @@ return 0; case SNDCTL_DSP_GETODELAY: + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); count = s->dma_dac1.count; @@ -2226,8 +2274,8 @@ return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; @@ -2329,6 +2377,7 @@ down(&s->open_sem); } s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; + s->dma_dac1.enabled = 1; set_dac1_rate(s, 8000); spin_lock_irqsave(&s->lock, flags); s->sctrl &= ~SCTRL_P1FMT; @@ -2608,6 +2657,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2800,12 +2850,26 @@ s->ctrl |= CTRL_GPIO_OUT0; printk(KERN_INFO PFX "Running On Gateway 2000 Solo 2510 - Amp On \n"); } + s->gameport.io = s->gameport.size = 0; if ((joystick[devindex] & ~0x18) == 0x200) { - if (check_region(joystick[devindex], JOY_EXTENT)) + if (!request_region(joystick[devindex], JOY_EXTENT, "es1371")) printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]); else { s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); + s->gameport.io = joystick[devindex]; + s->gameport.size = JOY_EXTENT; } + } else if (joystick[devindex] == 1) { + for (i = 0x218; i >= 0x200; i -= 0x08) { + if (request_region(i, JOY_EXTENT, "es1371")) { + s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); + s->gameport.io = i; + s->gameport.size = JOY_EXTENT; + break; + } + } + if (!s->gameport.io) + printk(KERN_ERR PFX "no free joystick address found\n"); } s->sctrl = 0; cssr = 0; @@ -2830,7 +2894,7 @@ pci_set_master(pcidev); /* enable bus mastering */ /* if we are a 5880 turn on the AC97 */ if (s->vendor == PCI_VENDOR_ID_ENSONIQ && - ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev == CT5880REV_CT5880_C) || + ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev >= CT5880REV_CT5880_C) || (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) || (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) { cssr |= CSTAT_5880_AC97_RST; @@ -2853,7 +2917,7 @@ src_init(s); /* codec init */ if (!ac97_probe_codec(&s->codec)) - goto err_dev4; + goto err_gp; /* set default values */ fs = get_fs(); @@ -2873,6 +2937,8 @@ set_fs(fs); /* turn on S/PDIF output driver if requested */ outl(cssr, s->io+ES1371_REG_STATUS); + /* register gameport */ + gameport_register_port(&s->gameport); /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ @@ -2882,6 +2948,9 @@ devindex++; return 0; + err_gp: + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); err_dev4: unregister_sound_dsp(s->dev_dac); err_dev3: @@ -2913,6 +2982,10 @@ outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ synchronize_irq(); free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } release_region(s->io, ES1371_EXTENT); unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->codec.dev_mixer); @@ -2942,7 +3015,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO PFX "version v0.27 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO PFX "version v0.30 time " __TIME__ " " __DATE__ "\n"); return pci_module_init(&es1371_driver); } diff -u --recursive --new-file v2.4.3/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.3/linux/drivers/sound/esssolo1.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/sound/esssolo1.c Thu Apr 12 12:16:36 2001 @@ -3,7 +3,7 @@ /* * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -70,6 +70,13 @@ * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.17 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 31.01.2001 0.18 Register/Unregister gameport, original patch from + * Nathaniel Daw <daw@cs.cmu.edu> + * Fix SETTRIGGER non OSS API conformity + * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro + * for abs. Bug report by Andrew Morton <andrewm@uow.edu.au> */ /*****************************************************************************/ @@ -98,12 +105,40 @@ #include "dm.h" +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS /* --------------------------------------------------------------------- */ +/* prevent picking up a bogus abs macro */ +#undef abs +extern inline int abs(int x) +{ + if (x < 0) + return -x; + return x; +} + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_ESS #define PCI_VENDOR_ID_ESS 0x125d #endif @@ -154,7 +189,7 @@ int dev_dmfm; /* hardware resources */ - unsigned long iobase, sbbase, vcbase, ddmabase, mpubase, gpbase; /* long for SPARC */ + unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */ unsigned int irq; /* mixer registers */ @@ -196,6 +231,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -211,6 +247,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -465,6 +503,7 @@ db->numfrag = db->ossmaxfrags; db->fragsamples = db->fragsize >> sample_shift; db->dmasize = db->numfrag << db->fragshift; + db->enabled = 1; return 0; } @@ -1024,7 +1063,8 @@ read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt); #endif if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); #ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" @@ -1071,7 +1111,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); #ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n", read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc)); @@ -1126,7 +1167,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1154,7 +1196,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); @@ -1370,27 +1413,33 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; + s->dma_dac.enabled = 1; start_adc(s); if (inb(s->ddmabase+15) & 1) printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n"); - } else + } else { + s->dma_dac.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) return ret; + s->dma_dac.enabled = 1; start_dac(s); - } else + } else { + s->dma_dac.enabled = 0; stop_dac(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; @@ -1406,8 +1455,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1424,8 +1473,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); count = s->dma_dac.count; @@ -1437,8 +1486,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1452,8 +1501,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; @@ -1606,7 +1655,9 @@ s->clkdiv = 96 | 0x80; s->ena = 0; s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + s->dma_dac.enabled = 1; s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); prog_codec(s); @@ -1933,6 +1984,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2281,7 +2333,8 @@ s->vcbase = pci_resource_start(pcidev, 2); s->ddmabase = s->vcbase + DDMABASE_OFFSET; s->mpubase = pci_resource_start(pcidev, 3); - s->gpbase = pci_resource_start(pcidev, 4); + s->gameport.io = pci_resource_start(pcidev, 4); + s->gameport.size = pci_resource_len(pcidev,4); s->irq = pcidev->irq; if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { printk(KERN_ERR "solo1: io ports in use\n"); @@ -2299,13 +2352,19 @@ printk(KERN_ERR "solo1: io ports in use\n"); goto err_region4; } + if (!s->gameport.size) + s->gameport.io = 0; + if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) { + printk(KERN_ERR "solo1: gameport io ports in use\n"); + s->gameport.io = s->gameport.size = 0; + } if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) { printk(KERN_ERR "solo1: irq %u in use\n", s->irq); goto err_irq; } if (pci_enable_device(pcidev)) goto err_irq; - printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1); + printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1); /* register devices */ if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) goto err_dev1; @@ -2317,6 +2376,8 @@ goto err_dev4; if (setup_solo1(s)) goto err; + /* register gameport */ + gameport_register_port(&s->gameport); /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ @@ -2340,6 +2401,8 @@ printk(KERN_ERR "solo1: initialisation error\n"); free_irq(s->irq, s); err_irq: + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); release_region(s->iobase, IOBASE_EXTENT); err_region4: release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); @@ -2366,6 +2429,10 @@ synchronize_irq(); pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */ free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } release_region(s->iobase, IOBASE_EXTENT); release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); release_region(s->ddmabase, DDMABASE_EXTENT); @@ -2397,7 +2464,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.16 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.18 time " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&solo1_driver)) { pci_unregister_driver(&solo1_driver); return -ENODEV; diff -u --recursive --new-file v2.4.3/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.3/linux/drivers/sound/i810_audio.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/sound/i810_audio.c Fri Apr 6 10:51:19 2001 @@ -101,8 +101,11 @@ #endif static int ftsodell=0; +static int strict_clocking=0; static unsigned int clocking=48000; +//#define DEBUG +//#define DEBUG2 #define ADC_RUNNING 1 #define DAC_RUNNING 2 @@ -169,6 +172,7 @@ #define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ #define DMA_INT_LVI (1<<2) /* last valid done */ #define DMA_INT_CELV (1<<1) /* last valid is current */ +#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ #define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI) /* interrupts for the whole chip */ @@ -183,7 +187,7 @@ #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI) -#define DRIVER_VERSION "0.01" +#define DRIVER_VERSION "0.02" /* magic numbers to protect our data structures */ #define I810_CARD_MAGIC 0x5072696E /* "Prin" */ @@ -247,7 +251,7 @@ struct dmabuf { /* wave sample stuff */ unsigned int rate; - unsigned char fmt, enable; + unsigned char fmt, enable, trigger; /* hardware channel */ struct i810_channel *read_channel; @@ -277,10 +281,9 @@ /* OSS stuff */ unsigned mapped:1; unsigned ready:1; - unsigned endcleared:1; unsigned update_flag; - unsigned ossfragshift; - int ossmaxfrags; + unsigned ossfragsize; + unsigned ossmaxfrags; unsigned subdivision; } dmabuf; }; @@ -408,8 +411,11 @@ /* * Adjust for misclocked crap */ - rate = ( rate * clocking)/48000; + if(strict_clocking && rate < 8000) { + rate = 8000; + dmabuf->rate = (rate * 48000)/clocking; + } if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE)) { @@ -456,6 +462,10 @@ */ rate = ( rate * clocking)/48000; + if(strict_clocking && rate < 8000) { + rate = 8000; + dmabuf->rate = (rate * 48000)/clocking; + } if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE)) { @@ -478,34 +488,10 @@ return dmabuf->rate; } -/* prepare channel attributes for playback */ -static void i810_play_setup(struct i810_state *state) -{ -// struct dmabuf *dmabuf = &state->dmabuf; -// struct i810_channel *channel = dmabuf->channel; - /* Fixed format. .. */ - //if (dmabuf->fmt & I810_FMT_16BIT) - //if (dmabuf->fmt & I810_FMT_STEREO) -} - -/* prepare channel attributes for recording */ -static void i810_rec_setup(struct i810_state *state) -{ -// u16 w; -// struct i810_card *card = state->card; -// struct dmabuf *dmabuf = &state->dmabuf; -// struct i810_channel *channel = dmabuf->channel; - - /* Enable AC-97 ADC (capture) */ -// if (dmabuf->fmt & I810_FMT_16BIT) { -// if (dmabuf->fmt & I810_FMT_STEREO) -} - - /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state) +extern __inline__ unsigned i810_get_dma_addr(struct i810_state *state, int rec) { struct dmabuf *dmabuf = &state->dmabuf; unsigned int civ, offset; @@ -513,17 +499,13 @@ if (!dmabuf->enable) return 0; - if (dmabuf->enable & DAC_RUNNING) - c = dmabuf->write_channel; - else if (dmabuf->enable & ADC_RUNNING) + if (rec) c = dmabuf->read_channel; - else { - printk("i810_audio: invalid dmabuf->enable state in get_dma_addr\n"); - return 0; - } + else + c = dmabuf->write_channel; do { civ = inb(state->card->iobase+c->port+OFF_CIV); - offset = (civ + 1) * (dmabuf->dmasize/SG_LEN) - + offset = (civ + 1) * dmabuf->fragsize - 2 * inw(state->card->iobase+c->port+OFF_PICB); /* CIV changed before we read PICB (very seldom) ? * then PICB was rubbish, so try again */ @@ -532,22 +514,26 @@ return offset; } -static void resync_dma_ptrs(struct i810_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct i810_channel *c; - int offset; - - if(rec) { - c = dmabuf->read_channel; - } else { - c = dmabuf->write_channel; - } - offset = inb(state->card->iobase+c->port+OFF_CIV); - offset *= (dmabuf->dmasize/SG_LEN); - - dmabuf->hwptr=dmabuf->swptr = offset; -} +//static void resync_dma_ptrs(struct i810_state *state, int rec) +//{ +// struct dmabuf *dmabuf = &state->dmabuf; +// struct i810_channel *c; +// int offset; +// +// if(rec) { +// c = dmabuf->read_channel; +// } else { +// c = dmabuf->write_channel; +// } +// if(c==NULL) +// return; +// offset = inb(state->card->iobase+c->port+OFF_CIV); +// if(offset == inb(state->card->iobase+c->port+OFF_LVI)) +// offset++; +// offset *= dmabuf->fragsize; +// +// dmabuf->hwptr=dmabuf->swptr = offset; +//} /* Stop recording (lock held) */ extern __inline__ void __stop_adc(struct i810_state *state) @@ -575,12 +561,13 @@ struct i810_card *card = state->card; unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable && + (dmabuf->trigger & PCM_ENABLE_INPUT)) { + spin_lock_irqsave(&card->lock, flags); dmabuf->enable |= ADC_RUNNING; - outb((1<<4) | 1<<2 | 1, card->iobase + PI_CR); + outb((1<<4) | (1<<2) | 1, card->iobase + PI_CR); + spin_unlock_irqrestore(&card->lock, flags); } - spin_unlock_irqrestore(&card->lock, flags); } /* stop playback (lock held) */ @@ -609,12 +596,13 @@ struct i810_card *card = state->card; unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { + if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && + (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { + spin_lock_irqsave(&card->lock, flags); dmabuf->enable |= DAC_RUNNING; - outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR); + outb((1<<4) | (1<<2) | 1, card->iobase + PO_CR); + spin_unlock_irqrestore(&card->lock, flags); } - spin_unlock_irqrestore(&card->lock, flags); } #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) @@ -625,18 +613,29 @@ { struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf= NULL; - int order; + int order, size; struct page *page, *pend; - /* alloc as big a chunk as we can, FIXME: is this necessary ?? */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + /* If we don't have any oss frag params, then use our default ones */ + if(dmabuf->ossmaxfrags == 0) + dmabuf->ossmaxfrags = 4; + if(dmabuf->ossfragsize == 0) + dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags; + size = dmabuf->ossfragsize * dmabuf->ossmaxfrags; + + /* alloc enough to satisfy the oss params */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { + if ( (PAGE_SIZE<<order) > size ) + continue; if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, PAGE_SIZE << order, &dmabuf->dma_handle))) break; + } if (!rawbuf) return -ENOMEM; + #ifdef DEBUG printk("i810_audio: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf); @@ -677,52 +676,53 @@ struct dmabuf *dmabuf = &state->dmabuf; struct i810_channel *c; struct sg_item *sg; - unsigned bytepersec; - unsigned bufsize; unsigned long flags; int ret; - unsigned fragsize; + unsigned fragint; int i; spin_lock_irqsave(&state->card->lock, flags); - resync_dma_ptrs(state, rec); + if(dmabuf->enable & DAC_RUNNING) + __stop_dac(state); + if(dmabuf->enable & ADC_RUNNING) + __stop_adc(state); dmabuf->total_bytes = 0; dmabuf->count = dmabuf->error = 0; + dmabuf->swptr = dmabuf->hwptr = 0; spin_unlock_irqrestore(&state->card->lock, flags); /* allocate DMA buffer if not allocated yet */ - if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state))) - return ret; + if (dmabuf->rawbuf) + dealloc_dmabuf(state); + if ((ret = alloc_dmabuf(state))) + return ret; /* FIXME: figure out all this OSS fragment stuff */ - /* sample_shift is for 16 byte samples, add an extra shift for bytes */ - bytepersec = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1); - bufsize = PAGE_SIZE << dmabuf->buforder; - if (dmabuf->ossfragshift) { - if ((1000 << dmabuf->ossfragshift) < bytepersec) - dmabuf->fragshift = ld2(bytepersec/1000); - else - dmabuf->fragshift = dmabuf->ossfragshift; + /* I did, it now does what it should according to the OSS API. DL */ + dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder; + dmabuf->numfrag = SG_LEN; + dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag; + dmabuf->fragsamples = dmabuf->fragsize >> 1; + + memset(dmabuf->rawbuf, 0, dmabuf->dmasize); + + if(dmabuf->ossmaxfrags == 4) { + fragint = 8; + dmabuf->ossfragsize = dmabuf->dmasize>>2; + dmabuf->fragshift = 2; + } else if (dmabuf->ossmaxfrags == 8) { + fragint = 4; + dmabuf->ossfragsize = dmabuf->dmasize>>3; + dmabuf->fragshift = 3; + } else if (dmabuf->ossmaxfrags == 16) { + fragint = 2; + dmabuf->ossfragsize = dmabuf->dmasize>>4; + dmabuf->fragshift = 4; } else { - /* lets hand out reasonable big ass buffers by default */ - dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + fragint = 1; + dmabuf->ossfragsize = dmabuf->dmasize>>5; + dmabuf->fragshift = 5; } - dmabuf->numfrag = bufsize >> dmabuf->fragshift; - while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { - dmabuf->fragshift--; - dmabuf->numfrag = bufsize >> dmabuf->fragshift; - } - dmabuf->fragsize = 1 << dmabuf->fragshift; - if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) - dmabuf->numfrag = dmabuf->ossmaxfrags; - dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; - dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - - memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80, - dmabuf->dmasize); - - fragsize = bufsize / SG_LEN; /* * Now set up the ring */ @@ -737,24 +737,26 @@ * way (we might want more interrupts later..) */ - for(i=0;i<32;i++) + for(i=0;i<dmabuf->numfrag;i++) { - sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i); - sg->control=(fragsize>>sample_shift[dmabuf->fmt]); - sg->control|=CON_IOC; + sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i); + // the card will always be doing 16bit stereo + sg->control=dmabuf->fragsamples; + sg->control|=CON_BUFPAD; + // set us up to get IOC interrupts as often as needed to + // satisfy numfrag requirements, no more + if( ((i+1) % fragint) == 0) { + sg->control|=CON_IOC; + } sg++; } spin_lock_irqsave(&state->card->lock, flags); outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR); - outb(31, state->card->iobase+c->port+OFF_LVI); outb(0, state->card->iobase+c->port+OFF_CIV); + outb(0, state->card->iobase+c->port+OFF_LVI); + dmabuf->count = 0; - if (c == dmabuf->read_channel) { - i810_rec_setup(state); - } else { - i810_play_setup(state); - } spin_unlock_irqrestore(&state->card->lock, flags); if(c != dmabuf->write_channel) @@ -775,36 +777,115 @@ return 0; } -/* - * Clear the rest of the last i810 dma buffer, normally there is no rest - * because the OSS fragment size is the same as the size of this buffer. - */ -static void i810_clear_tail(struct i810_state *state) + +static void __i810_update_lvi(struct i810_state *state, int rec) { struct dmabuf *dmabuf = &state->dmabuf; - unsigned swptr; - unsigned char silence = (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80; - unsigned int len; - unsigned long flags; + int x, port; + + port = state->card->iobase; + if(rec) + port += dmabuf->read_channel->port; + else + port += dmabuf->write_channel->port; - spin_lock_irqsave(&state->card->lock, flags); - swptr = dmabuf->swptr; - spin_unlock_irqrestore(&state->card->lock, flags); + if(dmabuf->mapped) { + if(rec) + dmabuf->swptr = (dmabuf->hwptr + dmabuf->dmasize + - dmabuf->count) % dmabuf->dmasize; + else + dmabuf->swptr = (dmabuf->hwptr + dmabuf->count) + % dmabuf->dmasize; + } + /* + * two special cases, count == 0 on write + * means no data, and count == dmasize + * means no data on read, handle appropriately + */ + if(!rec && dmabuf->count == 0) { + outb(inb(port+OFF_CIV),port+OFF_LVI); + return; + } + if(rec && dmabuf->count == dmabuf->dmasize) { + outb(inb(port+OFF_CIV),port+OFF_LVI); + return; + } + /* swptr - 1 is the tail of our transfer */ + x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize; + x /= dmabuf->fragsize; + outb(x&31, port+OFF_LVI); +} - if(dmabuf->dmasize) - len = swptr % (dmabuf->dmasize/SG_LEN); - else - len = 0; - - memset(dmabuf->rawbuf + swptr, silence, len); +static void i810_update_lvi(struct i810_state *state, int rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + if(!dmabuf->ready) + return; spin_lock_irqsave(&state->card->lock, flags); - dmabuf->swptr += len; - dmabuf->count += len; + __i810_update_lvi(state, rec); spin_unlock_irqrestore(&state->card->lock, flags); +} - /* restart the dma machine in case it is halted */ - start_dac(state); +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ +static void i810_update_ptr(struct i810_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned hwptr; + int diff; + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + /* update hardware pointer */ + hwptr = i810_get_dma_addr(state, 1); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; +// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count += diff; + if (dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a read */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if(inb(state->card->iobase + PI_CIV) != + inb(state->card->iobase + PI_LVI)) { + printk(KERN_WARNING "i810_audio: DMA overrun on read\n"); + dmabuf->error++; + } + } + if (dmabuf->count > dmabuf->ossfragsize) + wake_up(&dmabuf->wait); + } + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + /* update hardware pointer */ + hwptr = i810_get_dma_addr(state, 0); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; +// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count -= diff; + if (dmabuf->count < 0) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a write */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if(inb(state->card->iobase + PO_CIV) != + inb(state->card->iobase + PO_LVI)) { + printk(KERN_WARNING "i810_audio: DMA overrun on write\n"); + printk("i810_audio: CIV %d, LVI %d, hwptr %x, " + "count %d\n", + inb(state->card->iobase + PO_CIV), + inb(state->card->iobase + PO_LVI), + dmabuf->hwptr, dmabuf->count); + dmabuf->error++; + } + } + if (dmabuf->count < (dmabuf->dmasize-dmabuf->ossfragsize)) + wake_up(&dmabuf->wait); + } } static int drain_dac(struct i810_state *state, int nonblock) @@ -815,7 +896,7 @@ unsigned long tmo; int count; - if (dmabuf->mapped || !dmabuf->ready) + if (!dmabuf->ready) return 0; add_wait_queue(&dmabuf->wait, &wait); @@ -825,6 +906,7 @@ current->state = TASK_INTERRUPTIBLE; spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); count = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); @@ -834,6 +916,10 @@ if (signal_pending(current)) break; + i810_update_lvi(state,0); + if (dmabuf->enable != DAC_RUNNING) + start_dac(state); + if (nonblock) { remove_wait_queue(&dmabuf->wait, &wait); current->state = TASK_RUNNING; @@ -841,7 +927,7 @@ } tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; - tmo >>= sample_shift[dmabuf->fmt]; + tmo >>= 1; if (!schedule_timeout(tmo ? tmo : 1) && tmo){ printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n"); break; @@ -855,88 +941,18 @@ return 0; } -/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void i810_update_ptr(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned hwptr, swptr; - int clear_cnt = 0; - int diff; - unsigned char silence; -// unsigned half_dmasize; - - /* update hardware pointer */ - hwptr = i810_get_dma_addr(state); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; -// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - - /* error handling and process wake up for DAC */ - if (dmabuf->enable == ADC_RUNNING) { - if (dmabuf->mapped) { - dmabuf->count -= diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - } else { - dmabuf->count += diff; - - if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun, we have no way to recover - it here, just stop the machine and let the process force hwptr - and swptr to sync */ - __stop_adc(state); - dmabuf->error++; - } - else if (!dmabuf->endcleared) { - swptr = dmabuf->swptr; - silence = (dmabuf->fmt & I810_FMT_16BIT ? 0 : 0x80); - if (dmabuf->count < (signed) dmabuf->fragsize) - { - clear_cnt = dmabuf->fragsize; - if ((swptr + clear_cnt) > dmabuf->dmasize) - clear_cnt = dmabuf->dmasize - swptr; - memset (dmabuf->rawbuf + swptr, silence, clear_cnt); - dmabuf->endcleared = 1; - } - } - if (dmabuf->count < (signed)dmabuf->dmasize/2) { - wake_up(&dmabuf->wait); - } - } - } - /* error handling and process wake up for DAC */ - if (dmabuf->enable == DAC_RUNNING) { - if (dmabuf->mapped) { - dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - } else { - dmabuf->count -= diff; - - if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun, we have no way to recover - it here, just stop the machine and let the process force hwptr - and swptr to sync */ - __stop_dac(state); - printk(KERN_WARNING "i810_audio: DMA overrun on send\n"); - dmabuf->error++; - } - if (dmabuf->count < (signed)dmabuf->dmasize/2) { - wake_up(&dmabuf->wait); - } - } - } -} - static void i810_channel_interrupt(struct i810_card *card) { - int i; - + int i, count; + +#ifdef DEBUG_INTERRUPTS + printk("CHANNEL "); +#endif for(i=0;i<NR_HW_CH;i++) { struct i810_state *state = card->states[i]; struct i810_channel *c; + struct dmabuf *dmabuf; unsigned long port = card->iobase; u16 status; @@ -944,35 +960,56 @@ continue; if(!state->dmabuf.ready) continue; - if(state->dmabuf.enable & DAC_RUNNING) - c=state->dmabuf.write_channel; + dmabuf = &state->dmabuf; + if(dmabuf->enable & DAC_RUNNING) + c=dmabuf->write_channel; else - c=state->dmabuf.read_channel; + c=dmabuf->read_channel; port+=c->port; status = inw(port + OFF_SR); - +#ifdef DEBUG_INTERRUPTS + printk("NUM %d PORT %lX IRQ ( ST%d ", c->num, c->port, status); +#endif if(status & DMA_INT_COMPLETE) { - int x; - /* Keep the card chasing its tail */ - outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI); i810_update_ptr(state); +#ifdef DEBUG_INTERRUPTS + printk("COMP%d ",x); +#endif } if(status & DMA_INT_LVI) { - /* Back to the start */ i810_update_ptr(state); - outb(0, port + OFF_CR); + wake_up(&dmabuf->wait); +#ifdef DEBUG_INTERRUPTS + printk("LVI "); +#endif + } + if(status & DMA_INT_DCH) + { + i810_update_ptr(state); + if(dmabuf->enable & DAC_RUNNING) + count = dmabuf->count; + else + count = dmabuf->dmasize - dmabuf->count; + if(count > 0) { + outb(inb(port+OFF_CR) | 1, port+OFF_CR); + } else { + wake_up(&dmabuf->wait); +#ifdef DEBUG_INTERRUPTS + printk("DCH - STOP "); +#endif + } } outw(status & DMA_INT_MASK, port + OFF_SR); } +#ifdef DEBUG_INTERRUPTS + printk(")\n"); +#endif } -static u32 jiff = 0; -static u32 jiff_count = 0; - static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct i810_card *card = (struct i810_card *)dev_id; @@ -1009,10 +1046,10 @@ struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; - unsigned swptr; + unsigned int swptr; int cnt; -#ifdef DEBUG +#ifdef DEBUG2 printk("i810_audio: i810_read called, count = %d\n", count); #endif @@ -1026,43 +1063,45 @@ dmabuf->ready = 0; dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); if (!dmabuf->read_channel) { - return -ENODEV; + return -EBUSY; } } if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; + dmabuf->trigger &= ~PCM_ENABLE_OUTPUT; ret = 0; while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->count > (signed) dmabuf->dmasize) { - /* buffer overrun, we are recovering from sleep_on_timeout, - resync hwptr and swptr, make process flush the buffer */ - dmabuf->count = dmabuf->dmasize; - dmabuf->swptr = dmabuf->hwptr; - } swptr = dmabuf->swptr; - cnt = dmabuf->dmasize - swptr; - if (dmabuf->count < cnt) - cnt = dmabuf->count; + if (dmabuf->count > dmabuf->dmasize) { + dmabuf->count = 0; + } + cnt = dmabuf->count; + if(cnt > (dmabuf->dmasize - swptr)) + cnt = dmabuf->dmasize - swptr; spin_unlock_irqrestore(&state->card->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { unsigned long tmo; - /* buffer is empty, start the dma machine and wait for data to be - recorded */ - start_adc(state); + // are we already running? only start us if we aren't running + // currently + i810_update_lvi(state,1); + if(!dmabuf->enable) { + dmabuf->trigger |= PCM_ENABLE_INPUT; + start_adc(state); + } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; return ret; } /* This isnt strictly right for the 810 but it'll do */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); - tmo >>= sample_shift[dmabuf->fmt]; + tmo >>= 1; /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1102,8 +1141,9 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(state); } + i810_update_lvi(state,1); + start_adc(state); return ret; } @@ -1115,10 +1155,10 @@ struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; - unsigned swptr; - int cnt; + unsigned int swptr = 0; + int cnt, x; -#ifdef DEBUG +#ifdef DEBUG2 printk("i810_audio: i810_write called, count = %d\n", count); #endif @@ -1132,25 +1172,23 @@ dmabuf->ready = 0; dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); if(!dmabuf->write_channel) - return -ENODEV; + return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + dmabuf->trigger &= ~PCM_ENABLE_INPUT; ret = 0; while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); + swptr = dmabuf->swptr; if (dmabuf->count < 0) { - /* buffer underrun, we are recovering from sleep_on_timeout, - resync hwptr and swptr */ dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; } - swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; - if (dmabuf->count + cnt > dmabuf->dmasize) + if(cnt > (dmabuf->dmasize - dmabuf->count)) cnt = dmabuf->dmasize - dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); @@ -1158,16 +1196,20 @@ cnt = count; if (cnt <= 0) { unsigned long tmo; - /* buffer is full, start the dma machine and wait for data to be - played */ - start_dac(state); + // There is data waiting to be played + i810_update_lvi(state,0); + if(!dmabuf->enable && dmabuf->count) { + /* force the starting incase SETTRIGGER has been used */ + /* to stop it, otherwise this is a deadlock situation */ + dmabuf->trigger |= PCM_ENABLE_OUTPUT; + start_dac(state); + } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; return ret; } /* Not strictly correct but works */ - tmo = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1); - tmo = dmabuf->dmasize * HZ / tmo; + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 4); /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1184,6 +1226,7 @@ #endif /* a buffer underrun, we delay the recovery until next time the while loop begin and we REALLY have data to play */ + //return ret; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; @@ -1191,7 +1234,7 @@ } continue; } - if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) { if (!ret) ret = -EFAULT; return ret; } @@ -1201,14 +1244,21 @@ spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; dmabuf->count += cnt; - dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; buffer += cnt; ret += cnt; - start_dac(state); } + if (swptr % dmabuf->fragsize) { + x = dmabuf->fragsize - (swptr % dmabuf->fragsize); + if((x + dmabuf->count) < dmabuf->dmasize) + memset(dmabuf->rawbuf + swptr, '\0', x); + } + i810_update_lvi(state,0); + if (!dmabuf->enable && dmabuf->count >= dmabuf->ossfragsize) + start_dac(state); + return ret; } @@ -1220,21 +1270,9 @@ unsigned long flags; unsigned int mask = 0; - if (file->f_mode & FMODE_WRITE) { - if (!dmabuf->write_channel) - return 0; - if (!dmabuf->ready && prog_dmabuf(state, 0)) - return 0; - poll_wait(file, &dmabuf->wait, wait); - } else { - // don't do both read and write paths or we won't get woke up properly - // when we have a file with both permissions - if (!dmabuf->read_channel) - return 0; - if (!dmabuf->ready && prog_dmabuf(state, 1)) - return 0; - poll_wait(file, &dmabuf->wait, wait); - } + if(!dmabuf->ready) + return 0; + poll_wait(file, &dmabuf->wait, wait); spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) { @@ -1262,22 +1300,24 @@ int ret = -EINVAL; unsigned long size; - /* - * Until we figure out a few problems - */ - lock_kernel(); if (vma->vm_flags & VM_WRITE) { - if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) - goto out; - if ((ret = prog_dmabuf(state, 0)) != 0) - goto out; - } else if (vma->vm_flags & VM_READ) { - if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) + if (!dmabuf->write_channel && + (dmabuf->write_channel = + state->card->alloc_pcm_channel(state->card)) == NULL) { + ret = -EBUSY; goto out; - if ((ret = prog_dmabuf(state, 1)) != 0) + } + } + if (vma->vm_flags & VM_READ) { + if (!dmabuf->read_channel && + (dmabuf->read_channel = + state->card->alloc_rec_pcm_channel(state->card)) == NULL) { + ret = -EBUSY; goto out; - } else + } + } + if ((ret = prog_dmabuf(state, 0)) != 0) goto out; ret = -EINVAL; @@ -1291,9 +1331,13 @@ size, vma->vm_page_prot)) goto out; dmabuf->mapped = 1; + if(vma->vm_flags & VM_WRITE) + dmabuf->count = dmabuf->dmasize; + else + dmabuf->count = 0; ret = 0; #ifdef DEBUG - printk("i810_audio: mmap'ed %d bytes of data space\n", size); + printk("i810_audio: mmap'ed %ld bytes of data space\n", size); #endif out: unlock_kernel(); @@ -1312,41 +1356,52 @@ mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || ((file->f_mode & FMODE_READ) && dmabuf->mapped); #ifdef DEBUG - printk("i810_audio: i810_ioctl, command = %2d, arg = 0x%08x\n", - _IOC_NR(cmd), arg ? *(int *)arg : 0); + printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0); #endif switch (cmd) { case OSS_GETVERSION: +#ifdef DEBUG + printk("OSS_GETVERSION\n"); +#endif return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: +#ifdef DEBUG + printk("SNDCTL_DSP_RESET\n"); +#endif /* FIXME: spin_lock ? */ - if (file->f_mode & FMODE_WRITE) { + if (dmabuf->enable == DAC_RUNNING) { stop_dac(state); - synchronize_irq(); - dmabuf->ready = 0; - resync_dma_ptrs(state, 0); - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; } - if (file->f_mode & FMODE_READ) { + if (dmabuf->enable == ADC_RUNNING) { stop_adc(state); - synchronize_irq(); - resync_dma_ptrs(state, 1); - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; } + synchronize_irq(); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; return 0; case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(state, file->f_flags & O_NONBLOCK); +#ifdef DEBUG + printk("SNDCTL_DSP_SYNC\n"); +#endif + if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK) + return 0; + drain_dac(state, 0); + stop_dac(state); + synchronize_irq(); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; return 0; case SNDCTL_DSP_SPEED: /* set smaple rate */ +#ifdef DEBUG + printk("SNDCTL_DSP_SPEED\n"); +#endif if (get_user(val, (int *)arg)) return -EFAULT; if (val >= 0) { @@ -1368,71 +1423,68 @@ return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ +#ifdef DEBUG + printk("SNDCTL_DSP_STEREO\n"); +#endif if (get_user(val, (int *)arg)) return -EFAULT; - if(val==0) - return -EINVAL; - if (file->f_mode & FMODE_WRITE) { + if(val==0) { + ret = -EINVAL; + } else { + ret = 1; + } + if (dmabuf->enable & DAC_RUNNING) { stop_dac(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_STEREO; } - if (file->f_mode & FMODE_READ) { + if (dmabuf->enable & ADC_RUNNING) { stop_adc(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_STEREO; } - return 0; + return ret; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) return val; - return put_user(dmabuf->fragsize, (int *)arg); } if (file->f_mode & FMODE_READ) { if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) return val; - return put_user(dmabuf->fragsize, (int *)arg); } +#ifdef DEBUG + printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->ossfragsize); +#endif + return put_user(dmabuf->ossfragsize, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ +#ifdef DEBUG + printk("SNDCTL_DSP_GETFMTS\n"); +#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_WRITE) { - stop_dac(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_16BIT; - } - if (file->f_mode & FMODE_READ) { - stop_adc(state); - dmabuf->ready = 0; - dmabuf->fmt |= I810_FMT_16BIT; - } - } +#ifdef DEBUG + printk("SNDCTL_DSP_SETFMT\n"); +#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_WRITE) { - stop_dac(state); - dmabuf->ready = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(state); - dmabuf->ready = 0; - } - } +#ifdef DEBUG + printk("SNDCTL_DSP_CHANNELS\n"); +#endif return put_user(2, (int *)arg); - case SNDCTL_DSP_POST: - /* FIXME: the same as RESET ?? */ + case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ + /* we update the swptr to the end of the last sg segment then return */ +#ifdef DEBUG + printk("SNDCTL_DSP_POST\n"); +#endif + if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING)) + return 0; + if((dmabuf->swptr % dmabuf->fragsize) != 0) { + val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize); + dmabuf->swptr += val; + dmabuf->count += val; + } return 0; case SNDCTL_DSP_SUBDIVIDE: @@ -1442,6 +1494,9 @@ return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; +#ifdef DEBUG + printk("SNDCTL_DSP_SUBDIVIDE %d\n", val); +#endif dmabuf->subdivision = val; dmabuf->ready = 0; return 0; @@ -1450,15 +1505,27 @@ if (get_user(val, (int *)arg)) return -EFAULT; - dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossfragsize = 1<<(val & 0xffff); dmabuf->ossmaxfrags = (val >> 16) & 0xffff; - if (dmabuf->ossfragshift < 4) - dmabuf->ossfragshift = 4; - if (dmabuf->ossfragshift > 15) - dmabuf->ossfragshift = 15; - if (dmabuf->ossmaxfrags < 4) + if (dmabuf->ossmaxfrags <= 4) dmabuf->ossmaxfrags = 4; + else if (dmabuf->ossmaxfrags <= 8) + dmabuf->ossmaxfrags = 8; + else if (dmabuf->ossmaxfrags <= 16) + dmabuf->ossmaxfrags = 16; + else + dmabuf->ossmaxfrags = 32; + val = dmabuf->ossfragsize * dmabuf->ossmaxfrags; + if (val < 16384) + val = 16384; + if (val > 65536) + val = 65536; + dmabuf->ossfragsize = val/dmabuf->ossmaxfrags; dmabuf->ready = 0; +#ifdef DEBUG + printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, + dmabuf->ossfragsize, dmabuf->ossmaxfrags); +#endif return 0; @@ -1469,13 +1536,42 @@ return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); - abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->dmasize - dmabuf->count; - abinfo.fragstotal = dmabuf->numfrag; - abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + abinfo.fragsize = dmabuf->ossfragsize; + abinfo.fragstotal = dmabuf->ossmaxfrags; + if(dmabuf->mapped) + abinfo.bytes = dmabuf->count; + else + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragments = abinfo.bytes / dmabuf->ossfragsize; spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes, + abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); +#endif return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.ptr = dmabuf->hwptr; + cinfo.blocks = (dmabuf->dmasize - dmabuf->count)/dmabuf->ossfragsize; + if (dmabuf->mapped) { + dmabuf->count = (dmabuf->dmasize - + (dmabuf->count & (dmabuf->ossfragsize-1))); + __i810_update_lvi(state, 0); + } + spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, + cinfo.blocks, cinfo.ptr, dmabuf->count); +#endif + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; @@ -1483,87 +1579,111 @@ return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); - abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->count; - abinfo.fragstotal = dmabuf->numfrag; - abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + abinfo.fragsize = dmabuf->ossfragsize; + abinfo.fragstotal = dmabuf->ossmaxfrags; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragments = abinfo.bytes / dmabuf->ossfragsize; spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes, + abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); +#endif return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + i810_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count/dmabuf->ossfragsize; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) { + dmabuf->count &= dmabuf->ossfragsize-1; + __i810_update_lvi(state, 1); + } + spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, + cinfo.blocks, cinfo.ptr, dmabuf->count); +#endif + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_NONBLOCK: +#ifdef DEBUG + printk("SNDCTL_DSP_NONBLOCK\n"); +#endif file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETCAPS: +#ifdef DEBUG + printk("SNDCTL_DSP_GETCAPS\n"); +#endif return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, (int *)arg); case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, (int *)arg); +#ifdef DEBUG + printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger); +#endif + return put_user(dmabuf->trigger, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) return -EFAULT; - if (file->f_mode & FMODE_READ && val & PCM_ENABLE_INPUT) { - if (dmabuf->enable & DAC_RUNNING) - return -ENODEV; - if (!dmabuf->read_channel) { - dmabuf->ready = 0; - dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); - if (!dmabuf->read_channel) - return -ENODEV; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - start_adc(state); +#ifdef DEBUG + printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); +#endif + if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { + stop_adc(state); + } + if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) { + stop_dac(state); } - if (file->f_mode & FMODE_WRITE && val & PCM_ENABLE_OUTPUT) { - if (dmabuf->enable & ADC_RUNNING) - return -ENODEV; + dmabuf->trigger = val; + if(val & PCM_ENABLE_OUTPUT) { if (!dmabuf->write_channel) { dmabuf->ready = 0; dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); if (!dmabuf->write_channel) - return -ENODEV; + return -EBUSY; } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; - start_dac(state); + if (dmabuf->mapped) { + dmabuf->count = dmabuf->dmasize; + i810_update_lvi(state,0); + } + if (!dmabuf->enable && dmabuf->count > dmabuf->fragsize) + start_dac(state); + } + if(val & PCM_ENABLE_INPUT) { + if (!dmabuf->read_channel) { + dmabuf->ready = 0; + dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); + if (!dmabuf->read_channel) + return -EBUSY; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (dmabuf->mapped) { + dmabuf->count = 0; + i810_update_lvi(state,1); + } + if (!dmabuf->enable && dmabuf->count < + (dmabuf->dmasize - dmabuf->fragsize)) + start_adc(state); } return 0; - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = dmabuf->count >> dmabuf->fragshift; - cinfo.ptr = dmabuf->hwptr; - if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; - spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = dmabuf->count >> dmabuf->fragshift; - cinfo.ptr = dmabuf->hwptr; - if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; - spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - case SNDCTL_DSP_SETDUPLEX: +#ifdef DEBUG + printk("SNDCTL_DSP_SETDUPLEX\n"); +#endif return -EINVAL; case SNDCTL_DSP_GETODELAY: @@ -1573,16 +1693,27 @@ i810_update_ptr(state); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count); +#endif return put_user(val, (int *)arg); case SOUND_PCM_READ_RATE: +#ifdef DEBUG + printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate); +#endif return put_user(dmabuf->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: - return put_user((dmabuf->fmt & I810_FMT_STEREO) ? 2 : 1, - (int *)arg); +#ifdef DEBUG + printk("SOUND_PCM_READ_CHANNELS\n"); +#endif + return put_user(2, (int *)arg); case SOUND_PCM_READ_BITS: +#ifdef DEBUG + printk("SOUND_PCM_READ_BITS\n"); +#endif return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_MAPINBUF: @@ -1590,6 +1721,9 @@ case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: +#ifdef DEBUG + printk("SNDCTL_* -EINVAL\n"); +#endif return -EINVAL; } return -EINVAL; @@ -1621,7 +1755,7 @@ if (!state) return -ENODEV; - found_virt: +found_virt: /* initialize the virtual channel */ state->virt = i; state->card = card; @@ -1629,33 +1763,36 @@ init_waitqueue_head(&dmabuf->wait); init_MUTEX(&state->open_sem); file->private_data = state; + dmabuf->trigger = 0; /* allocate hardware channels */ if(file->f_mode & FMODE_READ) { if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) { kfree (card->states[i]); card->states[i] = NULL;; - return -ENODEV; + return -EBUSY; } - i810_set_adc_rate(state, 48000); + i810_set_adc_rate(state, 8000); + dmabuf->trigger |= PCM_ENABLE_INPUT; } if(file->f_mode & FMODE_WRITE) { if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { kfree (card->states[i]); card->states[i] = NULL;; - return -ENODEV; + return -EBUSY; } - i810_set_dac_rate(state, 48000); + i810_set_dac_rate(state, 8000); + dmabuf->trigger |= PCM_ENABLE_OUTPUT; } down(&state->open_sem); /* set default sample format. According to OSS Programmer's Guide /dev/dsp should be default to unsigned 8-bits, mono, with sample rate 8kHz and - /dev/dspW will accept 16-bits sample */ - dmabuf->fmt &= ~I810_FMT_MASK; - dmabuf->fmt |= I810_FMT_16BIT; - dmabuf->ossfragshift = 0; + /dev/dspW will accept 16-bits sample, but we don't support those so we + set it immediately to stereo and 16bit, which is all we do support */ + dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO; + dmabuf->ossfragsize = 0; dmabuf->ossmaxfrags = 0; dmabuf->subdivision = 0; @@ -1671,22 +1808,23 @@ struct dmabuf *dmabuf = &state->dmabuf; lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - } - /* stop DMA state machine and free DMA buffers/channels */ down(&state->open_sem); - if (dmabuf->enable & DAC_RUNNING) { - i810_clear_tail(state); - drain_dac(state, file->f_flags & O_NONBLOCK); + /* stop DMA state machine and free DMA buffers/channels */ + if(dmabuf->enable == DAC_RUNNING || + (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) { + if(drain_dac(state,file->f_mode & O_NDELAY)) { + up(&state->open_sem); + unlock_kernel(); + return -EBUSY; + } stop_dac(state); - dealloc_dmabuf(state); } if(dmabuf->enable & ADC_RUNNING) { stop_adc(state); - dealloc_dmabuf(state); } + dealloc_dmabuf(state); if (file->f_mode & FMODE_WRITE) { state->card->free_pcm_channel(state->card, dmabuf->write_channel->num); } @@ -1827,6 +1965,19 @@ if (ac97_probe_codec(codec) == 0) break; + /* power up everything, modify this when implementing power saving */ + i810_ac97_set(codec, AC97_POWER_CONTROL, + i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); + /* wait for analog ready */ + for (i=10; + i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); + i--) + { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/20); + } + + /* Don't attempt to get eid until powerup is complete */ eid = i810_ac97_get(codec, AC97_EXTENDED_ID); if(eid==0xFFFFFF) @@ -1845,18 +1996,6 @@ printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n"); else { - /* power up everything, modify this when implementing power saving */ - i810_ac97_set(codec, AC97_POWER_CONTROL, - i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); - /* wait for analog ready */ - for (i=10; - i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); - i--) - { - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/20); - } - /* Enable variable rate mode */ i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9); i810_ac97_set(codec,AC97_EXTENDED_STATUS, @@ -1996,6 +2135,7 @@ MODULE_DESCRIPTION("Intel 810 audio support"); MODULE_PARM(ftsodell, "i"); MODULE_PARM(clocking, "i"); +MODULE_PARM(strict_clocking, "i"); #define I810_MODULE_NAME "intel810_audio" @@ -2036,6 +2176,7 @@ init_waitqueue_head(&dmabuf->wait); init_MUTEX(&state->open_sem); dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; + dmabuf->trigger = PCM_ENABLE_OUTPUT; i810_set_dac_rate(state, 48000); if(prog_dmabuf(state, 0) != 0) { goto config_out_nodmabuf; @@ -2044,25 +2185,30 @@ goto config_out; } dmabuf->count = dmabuf->dmasize; + outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); save_flags(flags); cli(); start_dac(state); - offset = i810_get_dma_addr(state); + offset = i810_get_dma_addr(state, 0); mdelay(50); - new_offset = i810_get_dma_addr(state); + new_offset = i810_get_dma_addr(state, 0); stop_dac(state); outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); restore_flags(flags); i = new_offset - offset; +#ifdef DEBUG printk("i810_audio: %d bytes in 50 milliseconds\n", i); +#endif + if(i == 0) + goto config_out; i = i / 4 * 20; if (i > 48500 || i < 47500) { clocking = clocking * clocking / i; - printk("i810_audio: setting clocking to %d to compensate\n", clocking); + printk("i810_audio: setting clocking to %d\n", clocking); } -config_out_nodmabuf: - dealloc_dmabuf(state); config_out: + dealloc_dmabuf(state); +config_out_nodmabuf: state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); kfree(state); card->states[0] = NULL; diff -u --recursive --new-file v2.4.3/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.4.3/linux/drivers/sound/mad16.c Sat Dec 30 11:23:14 2000 +++ linux/drivers/sound/mad16.c Fri Apr 6 10:51:19 2001 @@ -423,72 +423,80 @@ DDB(printk("Detect using password = 0xE5\n")); - if (!detect_mad16()) /* No luck. Try different model */ - { - board_type = C928; + if (detect_mad16()) { + return 1; + } + + board_type = C928; - DDB(printk("Detect using password = 0xE2\n")); + DDB(printk("Detect using password = 0xE2\n")); - if (!detect_mad16()) - { - board_type = C929; - - DDB(printk("Detect using password = 0xE3\n")); - - if (!detect_mad16()) - { - if (inb(PASSWD_REG) != 0xff) - return 0; - - /* - * First relocate MC# registers to 0xe0e/0xe0f, disable password - */ - - outb((0xE4), PASSWD_REG); - outb((0x80), PASSWD_REG); - - board_type = C930; - - DDB(printk("Detect using password = 0xE4\n")); - - for (i = 0xf8d; i <= 0xf93; i++) - DDB(printk("port %03x = %02x\n", i, mad_read(i))); - if(!detect_mad16()) { - - /* The C931 has the password reg at F8D */ - outb((0xE4), 0xF8D); - outb((0x80), 0xF8D); - DDB(printk("Detect using password = 0xE4 for C931\n")); - - if (!detect_mad16()) { - board_type = C924; - c924pnp++; - DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); - if (!detect_mad16()) { - c924pnp=0; - return 0; - } - - DDB(printk("mad16.c: 82C924 PnP detected\n")); - } - } - else - DDB(printk("mad16.c: 82C930 detected\n")); - } else - DDB(printk("mad16.c: 82C929 detected\n")); - } else { - unsigned char model; + if (detect_mad16()) + { + unsigned char model; - if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) { - DDB(printk("mad16.c: Mozart detected\n")); - board_type = MOZART; - } else { - DDB(printk("mad16.c: 82C928 detected???\n")); - board_type = C928; - } + if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) { + DDB(printk("mad16.c: Mozart detected\n")); + board_type = MOZART; + } else { + DDB(printk("mad16.c: 82C928 detected???\n")); + board_type = C928; } + return 1; + } + + board_type = C929; + + DDB(printk("Detect using password = 0xE3\n")); + + if (detect_mad16()) + { + DDB(printk("mad16.c: 82C929 detected\n")); + return 1; + } + + if (inb(PASSWD_REG) != 0xff) + return 0; + + /* + * First relocate MC# registers to 0xe0e/0xe0f, disable password + */ + + outb((0xE4), PASSWD_REG); + outb((0x80), PASSWD_REG); + + board_type = C930; + + DDB(printk("Detect using password = 0xE4\n")); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); + + if(detect_mad16()) { + DDB(printk("mad16.c: 82C930 detected\n")); + return 1; } - return 1; + + /* The C931 has the password reg at F8D */ + outb((0xE4), 0xF8D); + outb((0x80), 0xF8D); + DDB(printk("Detect using password = 0xE4 for C931\n")); + + if (detect_mad16()) { + return 1; + } + + board_type = C924; + c924pnp++; + DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); + if (detect_mad16()) { + DDB(printk("mad16.c: 82C924 PnP detected\n")); + return 1; + } + + c924pnp=0; + + return 0; } static int __init probe_mad16(struct address_info *hw_config) diff -u --recursive --new-file v2.4.3/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c --- v2.4.3/linux/drivers/sound/maestro3.c Fri Mar 2 18:38:39 2001 +++ linux/drivers/sound/maestro3.c Wed Apr 11 19:02:38 2001 @@ -81,7 +81,7 @@ * do the real work. The kernel presumably jumps into each of them in turn. * These code images tend to have their own data area, and one can have * multiple data areas representing different states for each of the 'client - * instance' code portions. There is generaly a list in the kernel data + * instance' code portions. There is generally a list in the kernel data * that points to the data instances for a given piece of code. * * We've only been given the binary image for the 'minisrc', mini sample diff -u --recursive --new-file v2.4.3/linux/drivers/sound/miroaci.h linux/drivers/sound/miroaci.h --- v2.4.3/linux/drivers/sound/miroaci.h Sun Mar 12 19:13:06 2000 +++ linux/drivers/sound/miroaci.h Wed Dec 31 16:00:00 1969 @@ -1,5 +0,0 @@ -extern int aci_implied_cmd(unsigned char opcode); -extern int aci_write_cmd(unsigned char opcode, unsigned char parameter); -extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2); -extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter); -extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter); diff -u --recursive --new-file v2.4.3/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.4.3/linux/drivers/sound/sonicvibes.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/sound/sonicvibes.c Thu Apr 12 12:16:36 2001 @@ -3,7 +3,7 @@ /* * sonicvibes.c -- S3 Sonic Vibes audio driver. * - * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-2001 Thomas Sailer (t.sailer@alumni.ethz.ch) * * 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 @@ -88,6 +88,10 @@ * use Martin Mares' pci_assign_resource * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.28 More dma buffer initializations, patch from + * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> + * 31.01.2001 0.29 Register/Unregister gameport + * Fix SETTRIGGER non OSS API conformity * */ @@ -115,6 +119,23 @@ #include "dm.h" +#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) +#include <linux/gameport.h> +#else +struct gameport { + int io; + int size; +}; + +extern inline void gameport_register_port(struct gameport *gameport) +{ +} + +extern inline void gameport_unregister_port(struct gameport *gameport) +{ +} +#endif + /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -301,7 +322,7 @@ int dev_dmfm; /* hardware resources */ - unsigned long iosb, ioenh, iosynth, iomidi, iogame; /* long for SPARC */ + unsigned long iosb, ioenh, iosynth, iomidi; /* long for SPARC */ unsigned int iodmaa, iodmac, irq; /* mixer stuff */ @@ -340,6 +361,7 @@ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; + unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; @@ -355,6 +377,8 @@ unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; + + struct gameport gameport; }; /* --------------------------------------------------------------------- */ @@ -786,6 +810,7 @@ wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1); } spin_unlock_irqrestore(&s->lock, flags); + db->enabled = 1; db->ready = 1; return 0; } @@ -1343,7 +1368,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1382,7 +1408,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_adc(s); + if (s->dma_adc.enabled) + start_adc(s); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); @@ -1430,7 +1457,8 @@ if (cnt > count) cnt = count; if (cnt <= 0) { - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1470,7 +1498,8 @@ count -= cnt; buffer += cnt; ret += cnt; - start_dac(s); + if (s->dma_dac.enabled) + start_dac(s); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); @@ -1706,25 +1735,31 @@ if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) return ret; + s->dma_adc.enabled = 1; start_adc(s); - } else + } else { + s->dma_adc.enabled = 0; stop_adc(s); + } } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) return ret; + s->dma_dac.enabled = 1; start_dac(s); - } else + } else { + s->dma_dac.enabled = 0; stop_dac(s); + } } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; @@ -1740,8 +1775,8 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; @@ -1761,8 +1796,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); count = s->dma_dac.count; @@ -1774,8 +1809,8 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; + if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; @@ -1792,8 +1827,8 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; @@ -1915,6 +1950,7 @@ if ((minor & 0xf) == SND_DEV_DSP16) fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT; s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_adc.enabled = 1; set_adc_rate(s, 8000); } if (file->f_mode & FMODE_WRITE) { @@ -1922,6 +1958,7 @@ if ((minor & 0xf) == SND_DEV_DSP16) fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT; s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + s->dma_dac.enabled = 1; set_dac_rate(s, 8000); } set_fmt(s, fmtm, fmts); @@ -2212,6 +2249,7 @@ if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); + unlock_kernel(); return -EBUSY; } tmo = (count * HZ) / 3100; @@ -2517,13 +2555,14 @@ s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH); s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH); s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI); - s->iogame = pci_resource_start(pcidev, RESOURCE_GAME); s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA); s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; + s->gameport.io = pci_resource_start(pcidev, RESOURCE_GAME); + s->gameport.size = pci_resource_len(pcidev,RESOURCE_GAME); pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", - s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); + printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n", + s->iosb, s->ioenh, s->iosynth, s->iomidi, s->gameport.io, s->iodmaa, s->iodmac); s->irq = pcidev->irq; /* hack */ @@ -2549,6 +2588,12 @@ printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); goto err_region1; } + if (!s->gameport.size) + s->gameport.io = 0; + if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) { + printk(KERN_ERR "sv: gameport io ports in use\n"); + s->gameport.io = s->gameport.size = 0; + } if (pci_enable_device(pcidev)) goto err_irq; /* initialize codec registers */ @@ -2600,7 +2645,9 @@ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); } set_fs(fs); - /* store it in the driver field */ + /* register gameport */ + gameport_register_port(&s->gameport); + /* store it in the driver field */ pci_set_drvdata(pcidev, s); /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2619,6 +2666,8 @@ printk(KERN_ERR "sv: cannot register misc device\n"); free_irq(s->irq, s); err_irq: + if (s->gameport.io) + release_region(s->gameport.io, s->gameport.size); release_region(s->iosynth, SV_EXTENT_SYNTH); err_region1: release_region(s->iomidi, SV_EXTENT_MIDI); @@ -2635,29 +2684,33 @@ static void __devinit sv_remove(struct pci_dev *dev) { - struct sv_state *s = pci_get_drvdata(dev); + struct sv_state *s = pci_get_drvdata(dev); - if (!s) - return; - list_del(&s->devs); - outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ - synchronize_irq(); - inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ - wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ - /*outb(0, s->iodmaa + SV_DMA_RESET);*/ - /*outb(0, s->iodmac + SV_DMA_RESET);*/ - free_irq(s->irq, s); - release_region(s->iodmac, SV_EXTENT_DMA); - release_region(s->iodmaa, SV_EXTENT_DMA); - release_region(s->ioenh, SV_EXTENT_ENH); - release_region(s->iomidi, SV_EXTENT_MIDI); - release_region(s->iosynth, SV_EXTENT_SYNTH); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - unregister_sound_special(s->dev_dmfm); - kfree(s); - pci_set_drvdata(dev, NULL); + if (!s) + return; + list_del(&s->devs); + outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ + synchronize_irq(); + inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ + wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + /*outb(0, s->iodmaa + SV_DMA_RESET);*/ + /*outb(0, s->iodmac + SV_DMA_RESET);*/ + free_irq(s->irq, s); + if (s->gameport.io) { + gameport_unregister_port(&s->gameport); + release_region(s->gameport.io, s->gameport.size); + } + release_region(s->iodmac, SV_EXTENT_DMA); + release_region(s->iodmaa, SV_EXTENT_DMA); + release_region(s->ioenh, SV_EXTENT_ENH); + release_region(s->iomidi, SV_EXTENT_MIDI); + release_region(s->iosynth, SV_EXTENT_SYNTH); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_midi(s->dev_midi); + unregister_sound_special(s->dev_dmfm); + kfree(s); + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { @@ -2678,7 +2731,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.27 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.29 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); diff -u --recursive --new-file v2.4.3/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.4.3/linux/drivers/sound/sound_core.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/sound/sound_core.c Fri Apr 6 10:51:19 2001 @@ -168,7 +168,11 @@ spin_unlock(&sound_loader_lock); if(r<0) + { kfree(s); + return r; + } + if (r == low) sprintf (name_buf, "%s", name); else diff -u --recursive --new-file v2.4.3/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.3/linux/drivers/sound/trident.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/sound/trident.c Fri Apr 6 10:51:19 2001 @@ -2890,7 +2890,7 @@ { if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A) || (i*4 == T4D_START_A)) continue; - ali_registers.global_regs[i] = inl(TRID_REG(card, i*4)); + outl(ali_registers.global_regs[i], TRID_REG(card, i*4)); } //start HW channel diff -u --recursive --new-file v2.4.3/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c --- v2.4.3/linux/drivers/sound/vidc.c Wed Sep 27 13:39:23 2000 +++ linux/drivers/sound/vidc.c Fri Apr 13 20:26:07 2001 @@ -17,6 +17,7 @@ * We currently support a mixer device, but it is currently non-functional. */ +#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> @@ -82,6 +83,7 @@ static void (*old_mksound)(unsigned int hz, unsigned int ticks); extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); extern void vidc_update_filler(int bits, int channels); +extern int softoss_dev; static void vidc_mksound(unsigned int hz, unsigned int ticks) @@ -214,8 +216,8 @@ rate = VIDC_SOUND_CLOCK / hwrate; } - outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE); - outl(0xb1000000 | hwctrl, IO_VIDC_BASE); + vidc_writel(0xb0000000 | (hwrate - 2)); + vidc_writel(0xb1000000 | hwctrl); newsize = (10000 / hwrate) & ~3; if (newsize < 208) @@ -354,7 +356,7 @@ dma_interrupt = vidc_audio_dma_interrupt; vidc_sound_dma_irq(0, NULL, NULL); - outb(DMA_CR_E | 0x10, IOMD_SD0CR); + iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR); local_irq_restore(flags); } @@ -473,6 +475,9 @@ vidc_adev = adev; vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); +#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE) + softoss_dev = adev; +#endif return; irq_failed: diff -u --recursive --new-file v2.4.3/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.4.3/linux/drivers/sound/waveartist.c Sat Nov 11 18:33:14 2000 +++ linux/drivers/sound/waveartist.c Fri Apr 13 20:26:07 2001 @@ -1824,7 +1824,7 @@ io = ints[1]; irq = ints[2]; dma = ints[3]; - dma16 = ints[4]; + dma2 = ints[4]; return 1; } diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c --- v2.4.3/linux/drivers/sound/ymfpci.c Tue Mar 20 11:29:01 2001 +++ linux/drivers/sound/ymfpci.c Fri Apr 6 10:51:19 2001 @@ -1853,6 +1853,7 @@ return -ENXIO; } + unit = NULL; /* gcc warns */ for (list = ymf_devs.next; list != &ymf_devs; list = list->next) { unit = list_entry(list, ymfpci_t, ymf_devs); if (((unit->dev_audio ^ minor) & ~0x0F) == 0) @@ -2147,8 +2148,8 @@ ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); /* setup DSP instruction code */ - for (i = 0; i < YDSXG_DSPLENGTH; i++) - ymfpci_writel(codec, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2]); + for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) + ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); switch (codec->pci->device) { case PCI_DEVICE_ID_YAMAHA_724F: @@ -2163,11 +2164,11 @@ if (ver_1e) { /* setup control instruction code */ - for (i = 0; i < YDSXG_CTRLLENGTH; i++) - ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst1E[i >> 2]); + for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) + ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]); } else { - for (i = 0; i < YDSXG_CTRLLENGTH; i++) - ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + i, CntrlInst[i >> 2]); + for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) + ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]); } ymfpci_enable_dsp(codec); diff -u --recursive --new-file v2.4.3/linux/drivers/sound/ymfpci_image.h linux/drivers/sound/ymfpci_image.h --- v2.4.3/linux/drivers/sound/ymfpci_image.h Sun Dec 3 23:58:10 2000 +++ linux/drivers/sound/ymfpci_image.h Fri Apr 6 10:51:19 2001 @@ -1,7 +1,7 @@ #ifndef _HWMCODE_ #define _HWMCODE_ -static unsigned long int DspInst[] = { +static u32 DspInst[YDSXG_DSPLENGTH / 4] = { 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, @@ -12,7 +12,7 @@ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -static unsigned long int CntrlInst[] = { +static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, @@ -791,7 +791,7 @@ // 04/09 creat // 04/12 stop nise fix // 06/21 WorkingOff timming -static unsigned long int CntrlInst1E[] = { +static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, diff -u --recursive --new-file v2.4.3/linux/drivers/tc/Makefile linux/drivers/tc/Makefile --- v2.4.3/linux/drivers/tc/Makefile Fri Jun 25 17:38:40 1999 +++ linux/drivers/tc/Makefile Fri Apr 13 20:26:07 2001 @@ -7,27 +7,36 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -SUB_DIRS := -MOD_SUB_DIRS := -ALL_SUB_DIRS := - -L_TARGET := tc.a -L_OBJS := tc.o - -# Nasty trick as nobody references tcsyms.o, but we still want it linked. -# Stolen from pci Makefile -ifeq ($(CONFIG_MODULES),y) -O_TARGET = tc_syms.o -OX_OBJS = tcsyms.o -O_OBJS = tc.o -L_OBJS := tc_syms.o -else -L_OBJS := tc.o -endif - -ifdef CONFIG_ZS -L_OBJS += zs.o -endif +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := tc.o + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_TC) += tc.o +obj-$(CONFIG_ZS) += zs.o +obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) + +# Translate to Rules.make lists. + +L_TARGET := tc.a + +L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +LX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make +lk201-map.c: lk201-map.map + loadkeys --mktable lk201-map.map > lk201-map.c diff -u --recursive --new-file v2.4.3/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.3/linux/drivers/usb/devio.c Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/devio.c Fri Apr 6 15:51:50 2001 @@ -175,6 +175,7 @@ return NULL; memset(as, 0, assize); as->urb.number_of_packets = numisoframes; + spin_lock_init(&as->urb.lock); return as; } @@ -250,10 +251,6 @@ struct dev_state *ps = as->ps; struct siginfo sinfo; -#if 1 - printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", - urb->status, urb->error_count, urb->actual_length, urb->pipe); -#endif spin_lock(&ps->lock); list_del(&as->asynclist); list_add_tail(&as->asynclist, &ps->async_completed); diff -u --recursive --new-file v2.4.3/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.4.3/linux/drivers/usb/hub.c Sun Mar 25 18:14:21 2001 +++ linux/drivers/usb/hub.c Tue Apr 17 17:23:06 2001 @@ -98,15 +98,12 @@ hub->nerrors = 0; /* Something happened, let khubd figure it out */ - if (waitqueue_active(&khubd_wait)) { - /* Add the hub to the event queue */ - spin_lock_irqsave(&hub_event_lock, flags); - if (list_empty(&hub->event_list)) { - list_add(&hub->event_list, &hub_event_list); - wake_up(&khubd_wait); - } - spin_unlock_irqrestore(&hub_event_lock, flags); + spin_lock_irqsave(&hub_event_lock, flags); + if (list_empty(&hub->event_list)) { + list_add(&hub->event_list, &hub_event_list); + wake_up(&khubd_wait); } + spin_unlock_irqrestore(&hub_event_lock, flags); } static void usb_hub_power_on(struct usb_hub *hub) @@ -239,7 +236,6 @@ static void *hub_probe(struct usb_device *dev, unsigned int i, const struct usb_device_id *id) - { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; @@ -293,7 +289,7 @@ INIT_LIST_HEAD(&hub->event_list); hub->dev = dev; - init_MUTEX(&hub->khubd_sem); + atomic_set(&hub->refcnt, 1); /* Record the new hub's existence */ spin_lock_irqsave(&hub_event_lock, flags); @@ -322,6 +318,29 @@ return NULL; } +static void hub_get(struct usb_hub *hub) +{ + atomic_inc(&hub->refcnt); +} + +static void hub_put(struct usb_hub *hub) +{ + if (atomic_dec_and_test(&hub->refcnt)) { + if (hub->urb) { + usb_unlink_urb(hub->urb); + usb_free_urb(hub->urb); + hub->urb = NULL; + } + + if (hub->descriptor) { + kfree(hub->descriptor); + hub->descriptor = NULL; + } + + kfree(hub); + } +} + static void hub_disconnect(struct usb_device *dev, void *ptr) { struct usb_hub *hub = (struct usb_hub *)ptr; @@ -337,22 +356,7 @@ spin_unlock_irqrestore(&hub_event_lock, flags); - down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ - up(&hub->khubd_sem); - - if (hub->urb) { - usb_unlink_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } - - if (hub->descriptor) { - kfree(hub->descriptor); - hub->descriptor = NULL; - } - - /* Free the memory */ - kfree(hub); + hub_put(hub); } static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) @@ -406,6 +410,7 @@ if (usb_reset_device(dev)) return -1; + hub->urb->dev = dev; if (usb_submit_urb(hub->urb)) return -1; @@ -663,7 +668,7 @@ list_del(tmp); INIT_LIST_HEAD(tmp); - down(&hub->khubd_sem); /* never blocks, we were on list */ + hub_get(hub); spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -672,7 +677,7 @@ if (usb_hub_reset(hub)) { err("error resetting hub %d - disconnecting", dev->devnum); usb_hub_disconnect(dev); - up(&hub->khubd_sem); + hub_put(hub); continue; } @@ -748,7 +753,7 @@ usb_hub_power_on(hub); } } - up(&hub->khubd_sem); + hub_put(hub); } /* end while (1) */ spin_unlock_irqrestore(&hub_event_lock, flags); diff -u --recursive --new-file v2.4.3/linux/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.4.3/linux/drivers/usb/hub.h Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/hub.h Tue Apr 17 17:23:06 2001 @@ -109,7 +109,7 @@ struct usb_hub_descriptor *descriptor; - struct semaphore khubd_sem; + atomic_t refcnt; }; #endif diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in --- v2.4.3/linux/drivers/usb/serial/Config.in Mon Mar 19 17:21:54 2001 +++ linux/drivers/usb/serial/Config.in Fri Apr 6 15:51:50 2001 @@ -6,7 +6,9 @@ tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB if [ "$CONFIG_USB_SERIAL" != "n" ]; then - bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG + if [ "$CONFIG_USB_SERIAL" = "y" ]; then + bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG + fi bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c --- v2.4.3/linux/drivers/usb/serial/belkin_sa.c Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/serial/belkin_sa.c Fri Apr 6 15:51:50 2001 @@ -68,13 +68,13 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" #include "belkin_sa.h" @@ -607,3 +607,7 @@ module_exit (belkin_sa_exit); MODULE_DESCRIPTION("USB Belkin Serial converter driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/belkin_sa.h linux/drivers/usb/serial/belkin_sa.h --- v2.4.3/linux/drivers/usb/serial/belkin_sa.h Tue Mar 20 14:02:46 2001 +++ linux/drivers/usb/serial/belkin_sa.h Fri Apr 6 15:51:52 2001 @@ -43,7 +43,7 @@ #define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */ #define GOHUBS_VID 0x0921 /* GoHubs vendor id */ -#define GOHUBS_PID 0x0100 /* GoHubs single port serial converter's id (identical to the Peracom device) */ +#define GOHUBS_PID 0x1000 /* GoHubs single port serial converter's id (identical to the Peracom device) */ /* Vendor Request Interface */ #define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c --- v2.4.3/linux/drivers/usb/serial/digi_acceleport.c Tue Mar 20 14:02:46 2001 +++ linux/drivers/usb/serial/digi_acceleport.c Fri Apr 6 15:51:50 2001 @@ -241,14 +241,14 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/tqueue.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" @@ -2085,4 +2085,7 @@ MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>"); MODULE_DESCRIPTION("Digi AccelePort USB-2/USB-4 Serial Converter driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c --- v2.4.3/linux/drivers/usb/serial/empeg.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/serial/empeg.c Fri Apr 6 15:51:51 2001 @@ -55,12 +55,13 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> + #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" @@ -705,3 +706,7 @@ MODULE_AUTHOR("Gary Brubaker <xavyer@ix.netcom.com>"); MODULE_DESCRIPTION("USB Empeg Mark I/II Driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.4.3/linux/drivers/usb/serial/ftdi_sio.c Sun Mar 25 18:14:21 2001 +++ linux/drivers/usb/serial/ftdi_sio.c Fri Apr 6 15:51:51 2001 @@ -78,16 +78,15 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" - #include "ftdi_sio.h" @@ -881,3 +880,7 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>"); MODULE_DESCRIPTION("USB FTDI RS232 converters driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c --- v2.4.3/linux/drivers/usb/serial/io_edgeport.c Sun Mar 25 18:24:31 2001 +++ linux/drivers/usb/serial/io_edgeport.c Thu Apr 12 12:16:36 2001 @@ -223,6 +223,7 @@ * */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> @@ -239,15 +240,14 @@ #include <linux/serial.h> #include <linux/ioctl.h> #include <linux/proc_fs.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> - #include "usb-serial.h" #include "io_edgeport.h" @@ -279,6 +279,9 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"); MODULE_DESCRIPTION("Edgeport USB Serial Driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + #define MAX_NAME_LEN 64 @@ -474,47 +477,6 @@ - -#ifdef DEBUG - -/* Dump a buffer in HEX and Ascii */ -void DbgDisplayBuffer( void *pBuffer, __u32 Len ) -{ - char DisplayBuf[80]; - char * pStr = DisplayBuf; - __u8 *pBuf = pBuffer; - __u32 i; - __u8 d; - - while (Len) { - // Init for new line - memset( DisplayBuf, ' ', sizeof( DisplayBuf )); - DisplayBuf[79]=0; - pStr = DisplayBuf; - pStr[54] = '['; - pStr[71] = ']'; - - for ( i = 0; i < MIN(16, Len) ; i++ ) { - d = (__u8)(*pBuf >> 4); - pStr[(i*3)+0] = (char)((d < 10) ? d+'0' : d -10 + 'A'); - d = (__u8)(*pBuf & 0xf); - pStr[(i*3)+1] = (char)((d < 10) ? d+'0' : d -10 + 'A'); - - if (*pBuf > 31 && *pBuf < 127) - pStr[i+55]=*pBuf; - else - pStr[i+55]='.'; - - pBuf++; - } - Len -= i; - dbg("%s", DisplayBuf ); - } -} -#endif - - - // ************************************************************************ // ************************************************************************ // ************************************************************************ @@ -745,7 +707,6 @@ break; } -#ifdef DEBUG // Dump Product Info structure dbg("**Product Information:"); dbg(" ProductId %x", product_info->ProductId ); @@ -770,7 +731,6 @@ product_info->ManufactureDescDate[2]+1900); dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); -#endif } @@ -812,14 +772,7 @@ // process this interrupt-read even if there are no ports open if (length) { -#ifdef DEBUG - int i; - printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, data = ", length); - for (i = 0; i < length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, length, data); if (length > 1) { bytes_avail = data[0] | (data[1] << 8); @@ -894,13 +847,7 @@ if (urb->actual_length) { raw_data_length = urb->actual_length; -#ifdef DEBUG - { -// int i; - dbg (__FUNCTION__" - length = %d, data = ", raw_data_length); -// DbgDisplayBuffer((void *)data, raw_data_length); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, raw_data_length, data); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; @@ -976,10 +923,8 @@ dbg(__FUNCTION__); -#ifdef DEBUG CmdUrbs--; dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs); -#endif /* if this urb had a transfer buffer already (old transfer) free it */ @@ -1412,12 +1357,9 @@ // No need to check for wrap since we can not get to end of fifo in this part } -#ifdef DEBUG if (copySize) { - dbg (__FUNCTION__" - length = %d, data = ", copySize); - DbgDisplayBuffer((void *)data, copySize); + usb_serial_debug_data (__FILE__, __FUNCTION__, copySize, data); } -#endif send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port); @@ -1519,12 +1461,9 @@ fifo->count -= secondhalf; } -#ifdef DEBUG if (count) { - dbg (__FUNCTION__" - length = %d, data = ", count); - DbgDisplayBuffer((void *)&buffer[2], count); + usb_serial_debug_data (__FILE__, __FUNCTION__, count, &buffer[2]); } -#endif /* fill up the urb with all of our data and submit it */ FILL_BULK_URB (urb, edge_serial->serial->dev, @@ -2498,16 +2437,7 @@ urb_t *urb; int timeout; -#ifdef DEBUG - if (length) { - int i; - printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, buffer = ", length); - for (i = 0; i < length; ++i) { - printk ("%.2x ", buffer[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); /* Allocate our next urb */ urb = usb_alloc_urb (0); @@ -2857,7 +2787,6 @@ if (response < 1) { err("error in getting manufacturer descriptor"); } else { -#ifdef DEBUG char string[30]; dbg("**Manufacturer Descriptor"); dbg(" RomSize: %dK", edge_serial->manuf_descriptor.RomSize); @@ -2875,7 +2804,6 @@ dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); dbg(" IonConfig: %d", edge_serial->manuf_descriptor.IonConfig); -#endif } } @@ -3138,6 +3066,4 @@ module_init(edgeport_init); module_exit(edgeport_exit); - - diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c --- v2.4.3/linux/drivers/usb/serial/keyspan.c Fri Mar 2 17:50:22 2001 +++ linux/drivers/usb/serial/keyspan.c Thu Apr 12 12:16:36 2001 @@ -49,6 +49,7 @@ */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> @@ -62,13 +63,14 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> - -#define DEBUG -/* #ifdef CONFIG_USB_SERIAL_DEBUG */ - #define DEBUG -/* #endif */ #include <linux/usb.h> +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug; +#endif + #include "usb-serial.h" #include "keyspan.h" @@ -1671,3 +1673,7 @@ kfree(port->private); } } + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c --- v2.4.3/linux/drivers/usb/serial/keyspan_pda.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/serial/keyspan_pda.c Fri Apr 6 15:51:51 2001 @@ -67,13 +67,14 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/tqueue.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> + struct ezusb_hex_record { __u16 address; @@ -82,7 +83,6 @@ }; #include "keyspan_pda_fw.h" - #include "usb-serial.h" struct keyspan_pda_private { @@ -823,3 +823,7 @@ MODULE_AUTHOR("Brian Warner <warner@lothar.com>"); MODULE_DESCRIPTION("USB Keyspan PDA Converter driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c --- v2.4.3/linux/drivers/usb/serial/mct_u232.c Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/serial/mct_u232.c Fri Apr 6 15:51:52 2001 @@ -53,13 +53,13 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" #include "mct_u232.h" @@ -848,3 +848,7 @@ MODULE_PARM_DESC(write_blocking, "The write function will block to write out all data"); #endif + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c --- v2.4.3/linux/drivers/usb/serial/omninet.c Sun Mar 25 18:14:21 2001 +++ linux/drivers/usb/serial/omninet.c Fri Apr 6 15:51:52 2001 @@ -43,17 +43,14 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> - +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) ) - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> - #include "usb-serial.h" @@ -252,8 +249,7 @@ return; } -#ifdef DEBUG - if(header->oh_xxx != 0x30) { + if ((debug) && (header->oh_xxx != 0x30)) { if (urb->actual_length) { printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len); for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) { @@ -262,7 +258,6 @@ printk ("\n"); } } -#endif if (urb->actual_length && header->oh_len) { for (i = 0; i < header->oh_len; i++) { @@ -413,4 +408,7 @@ module_init(omninet_init); module_exit(omninet_exit); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.4.3/linux/drivers/usb/serial/usb-serial.h Mon Dec 11 13:17:29 2000 +++ linux/drivers/usb/serial/usb-serial.h Fri Apr 6 15:51:52 2001 @@ -219,15 +219,24 @@ static inline void usb_serial_debug_data (const char *file, const char *function, int size, const unsigned char *data) { -#ifdef CONFIG_USB_SERIAL_DEBUG int i; + + if (!debug) + return; + printk (KERN_DEBUG "%s: %s - length = %d, data = ", file, function, size); for (i = 0; i < size; ++i) { printk ("%.2x ", data[i]); } printk ("\n"); -#endif } + + +/* Use our own dbg macro */ +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + + #endif /* ifdef __LINUX_USB_SERIAL_H */ diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.3/linux/drivers/usb/serial/usbserial.c Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/serial/usbserial.c Fri Apr 6 15:51:52 2001 @@ -272,19 +272,24 @@ #include <linux/spinlock.h> #include <linux/list.h> #include <linux/smp_lock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> + +#include "usb-serial.h" + /* Module information */ MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); MODULE_DESCRIPTION("USB Serial Driver"); -#include "usb-serial.h" +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + #define MAX(a,b) (((a)>(b))?(a):(b)) @@ -364,6 +369,7 @@ static struct termios * serial_termios[SERIAL_TTY_MINORS]; static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ + LIST_HEAD(usb_serial_driver_list); diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.3/linux/drivers/usb/serial/visor.c Mon Mar 19 17:21:54 2001 +++ linux/drivers/usb/serial/visor.c Fri Apr 6 15:51:52 2001 @@ -92,16 +92,15 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" - #include "visor.h" #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -689,3 +688,7 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); MODULE_DESCRIPTION("USB HandSpring Visor driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c --- v2.4.3/linux/drivers/usb/serial/whiteheat.c Fri Mar 23 11:50:01 2001 +++ linux/drivers/usb/serial/whiteheat.c Fri Apr 6 15:51:52 2001 @@ -67,18 +67,16 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/usb.h> #ifdef CONFIG_USB_SERIAL_DEBUG - #define DEBUG + static int debug = 1; #else - #undef DEBUG + static int debug; #endif -#include <linux/usb.h> #include "usb-serial.h" - #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ - #include "whiteheat.h" /* WhiteHEAT specific commands */ #define CONNECT_TECH_VENDOR_ID 0x0710 @@ -634,3 +632,7 @@ MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); MODULE_DESCRIPTION("USB ConnectTech WhiteHEAT driver"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -u --recursive --new-file v2.4.3/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.4.3/linux/drivers/video/Config.in Thu Jan 4 13:00:55 2001 +++ linux/drivers/video/Config.in Fri Apr 13 20:31:32 2001 @@ -98,6 +98,14 @@ bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX fi fi + bool ' Epson 1355 framebuffer support' CONFIG_FB_E1355 + if [ "$CONFIG_FB_E1355" = "y" ]; then + hex ' Register Base Address' CONFIG_E1355_REG_BASE a8000000 + hex ' Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000 + fi + if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then + tristate ' Dreamcast Frame Buffer support' CONFIG_FB_DC + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_PCI" != "n" ]; then tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX diff -u --recursive --new-file v2.4.3/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.4.3/linux/drivers/video/Makefile Fri Dec 29 14:07:23 2000 +++ linux/drivers/video/Makefile Fri Apr 13 20:31:32 2001 @@ -100,6 +100,8 @@ obj-$(CONFIG_FB_SA1100) += sa1100fb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o +obj-$(CONFIG_FB_E1355) += epson1355fb.o fbgen.o +obj-$(CONFIG_FB_DC) += dcfb.o fbgen.o # Generic Low Level Drivers diff -u --recursive --new-file v2.4.3/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.4.3/linux/drivers/video/atyfb.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/video/atyfb.c Thu Apr 12 12:10:25 2001 @@ -3144,51 +3144,6 @@ vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ -#ifdef __sparc_v9__ - /* Align it as much as desirable */ - { - unsigned long j, align; - int max = -1; - - map_offset = off + size; - for (i = 0; fb->mmap_map[i].size; i++) { - if (fb->mmap_map[i].voff < off) - continue; - if (fb->mmap_map[i].voff >= map_offset) - break; - if (max < 0 || - fb->mmap_map[i].size > fb->mmap_map[max].size) - max = i; - } - if (max >= 0) { - j = fb->mmap_map[max].size; - if (fb->mmap_map[max].voff + j > map_offset) - j = map_offset - fb->mmap_map[max].voff; - for (align = 0x400000; align > PAGE_SIZE; align >>= 3) - if (j >= align && - !(fb->mmap_map[max].poff & (align - 1))) - break; - if (align > PAGE_SIZE) { - j = align; - align = j - ((vma->vm_start - + fb->mmap_map[max].voff - - off) & (j - 1)); - if (align != j) { - struct vm_area_struct *vmm; - - vmm = find_vma(current->mm, - vma->vm_start); - if (!vmm || vmm->vm_start - >= vma->vm_end + align) { - vma->vm_start += align; - vma->vm_end += align; - } - } - } - } - } -#endif - /* Each page, see which map applies */ for (page = 0; page < size; ) { map_size = 0; diff -u --recursive --new-file v2.4.3/linux/drivers/video/dcfb.c linux/drivers/video/dcfb.c --- v2.4.3/linux/drivers/video/dcfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/dcfb.c Fri Apr 13 20:31:32 2001 @@ -0,0 +1,504 @@ +/* + * $Id: dcfb.c,v 1.1 2001/04/01 15:02:51 yaegashi Exp $ + * SEGA Dreamcast framebuffer + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/nubus.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/io.h> + +#include <linux/fb.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> + +#define BORDERRGB 0xa05f8040 +#define DISPLAYMODE 0xa05f8044 +#define ALPHAMODE 0xa05f8048 +#define DISPLAYALIGN 0xa05f804c +#define BASEOFFSET1 0xa05f8050 +#define BASEOFFSET2 0xa05f8054 +#define DISPLAYSIZE 0xa05f805c +#define SYNCMODE 0xa05f80d0 +#define VERTICALRANGE 0xa05f80dc +#define HORIZPOSITION 0xa05f80ec +#define VERTPOSITION 0xa05f80f0 +#define PALETTEMODE 0xa05f8108 +#define VIDEOOUTPUT 0xa0702c00 + +static unsigned long dc_parm_vga_16bpp[] = { + DISPLAYMODE, 0x00800005, + BASEOFFSET1, 0, + BASEOFFSET2, 640*2, + DISPLAYSIZE, (1<<20)+((480-1)<<10)+(640*2/4-1), + SYNCMODE, 0x100, + VERTPOSITION, 0x00230023, + VERTICALRANGE, 0x00280208, + HORIZPOSITION, 0x00000090, + VIDEOOUTPUT, 0, + 0, 0, +}; + +static unsigned long dc_parm_vga_32bpp[] = { + DISPLAYMODE, 0x0080000d, + BASEOFFSET1, 0, + BASEOFFSET2, 640*4, + DISPLAYSIZE, (1<<20)+((480-1)<<10)+(640*4/4-1), + SYNCMODE, 0x100, + VERTPOSITION, 0x00230023, + VERTICALRANGE, 0x00280208, + HORIZPOSITION, 0x00000090, + VIDEOOUTPUT, 0, + 0, 0, +}; + +static unsigned long *dc_parm_vga[] = { + dc_parm_vga_16bpp, + dc_parm_vga_32bpp, +}; + +static unsigned long dc_parm_composite_16bpp[] = { + DISPLAYMODE, 0x00000005, + BASEOFFSET1, 0, + BASEOFFSET2, 640*2, + DISPLAYSIZE, ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1), + SYNCMODE, 0x150, + VERTPOSITION, 0x00120012, + VERTICALRANGE, 0x00240204, + HORIZPOSITION, 0x000000a4, + VIDEOOUTPUT, 0x300, + 0, 0, +}; + +static unsigned long dc_parm_composite_32bpp[] = { + DISPLAYMODE, 0x0000000d, + BASEOFFSET1, 0, + BASEOFFSET2, 640*4, + DISPLAYSIZE, ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1), + SYNCMODE, 0x150, + VERTPOSITION, 0x00120012, + VERTICALRANGE, 0x00240204, + HORIZPOSITION, 0x000000a4, + VIDEOOUTPUT, 0x300, + 0, 0, +}; + +static unsigned long *dc_parm_composite[] = { + dc_parm_composite_16bpp, + dc_parm_composite_32bpp, +}; + +static unsigned long dc_parm_interlace_16bpp[] = { + DISPLAYMODE, 0x00000005, + BASEOFFSET1, 0, + BASEOFFSET2, 640*2, + DISPLAYSIZE, ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1), + SYNCMODE, 0x150, + VERTPOSITION, 0x00120012, + VERTICALRANGE, 0x00240204, + HORIZPOSITION, 0x000000a4, + VIDEOOUTPUT, 0, + 0, 0, +}; + +static unsigned long dc_parm_interlace_32bpp[] = { + DISPLAYMODE, 0x0000000d, + BASEOFFSET1, 0, + BASEOFFSET2, 640*4, + DISPLAYSIZE, ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1), + SYNCMODE, 0x150, + VERTPOSITION, 0x00120012, + VERTICALRANGE, 0x00240204, + HORIZPOSITION, 0x000000a4, + VIDEOOUTPUT, 0, + 0, 0, +}; + +static unsigned long *dc_parm_interlace[] = { + dc_parm_interlace_16bpp, + dc_parm_interlace_32bpp, +}; + +struct dcfb_info { + struct fb_info_gen gen; +}; + +struct dcfb_par +{ + int x, y; + int bpp; +}; + +static struct dcfb_info fb_info; +static struct dcfb_par current_par; +static int current_par_valid = 0; +static struct display disp; + +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +static unsigned long **dc_parms; +static unsigned long dc_videobase, dc_videosize; +static struct fb_var_screeninfo default_var; + +int dcfb_init(void); + +static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info); +static void dcfb_encode_var(struct fb_var_screeninfo *var, + struct dcfb_par *par, + const struct fb_info *info); + + +/* + * Check cable type. + * 0: VGA, 2: RGB, 3: Composite + */ + +#define PCTRA 0xff80002c +#define PDTRA 0xff800030 + +static int dcfb_cable_check(void) +{ + unsigned long temp = ctrl_inl(PCTRA); + temp &= 0xfff0ffff; + temp |= 0x000a0000; + ctrl_outl(temp, PCTRA); + return (ctrl_inw(PDTRA)>>8)&3; +} + +static void dcfb_detect(void) +{ + struct dcfb_par par; + int cable = dcfb_cable_check(); + unsigned long **parm_list[4] = { + dc_parm_vga, dc_parm_vga, dc_parm_interlace, dc_parm_composite, + }; + char *cable_name[] = { "VGA", "VGA", "Interlace", "Composite", }; + + dc_videobase = 0xa5000000; + dc_videosize = 0x00200000; + + par.x = 640; + par.y = 480; + par.bpp = 32; + dc_parms = parm_list[cable]; + printk(KERN_INFO "Dreamcast video cable detected: %s.\n", cable_name[cable]); + + dcfb_set_par(&par, NULL); + dcfb_encode_var(&default_var, &par, NULL); +} + +static int dcfb_encode_fix(struct fb_fix_screeninfo *fix, + struct dcfb_par *par, + const struct fb_info *info) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, "SEGA Dreamcast"); + fix->smem_start = dc_videobase; + fix->smem_len = dc_videosize; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + + switch(par->bpp) { + default: + case 16: + fix->line_length = par->x*2; + break; + case 32: + fix->line_length = par->x*4; + break; + } + + return 0; +} + + +static int dcfb_decode_var(struct fb_var_screeninfo *var, + struct dcfb_par *par, + const struct fb_info *info) +{ + par->x = var->xres; + par->y = var->yres; + par->bpp = var->bits_per_pixel; + return 0; +} + + +static void dcfb_encode_var(struct fb_var_screeninfo *var, + struct dcfb_par *par, + const struct fb_info *info) +{ + memset(var, 0, sizeof(*var)); + + var->xres = par->x; + var->yres = par->y; + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate = 0; + var->height = -1; + var->width = -1; + var->vmode = FB_VMODE_NONINTERLACED; + var->pixclock = 0; + var->sync = 0; + var->left_margin = 0; + var->right_margin = 0; + var->upper_margin = 0; + var->lower_margin = 0; + var->hsync_len = 0; + var->vsync_len = 0; + + switch (var->bits_per_pixel) { + + case 16: /* RGB 565 */ + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; +} + + +static void dcfb_get_par(struct dcfb_par *par, const struct fb_info *info) +{ + *par = current_par; +} + + +static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info) +{ + unsigned long a, d, *p; + + current_par = *par; + current_par_valid = 1; + + switch(par->bpp) { + default: + case 16: + p = dc_parms[0]; + break; + case 32: + p = dc_parms[1]; + break; + } + + ctrl_outl(0, 0xa05f8008); /* reset? */ + ctrl_outl(0, BORDERRGB); + + while(1) { + a = *p++; d = *p++; + if (!a) break; + ctrl_outl(d, a); + } + +} + +static struct { + u_int red, green, blue; +} palette[256]; + +static int dcfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + *transp = 0; + + return 0; +} + + +static int dcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + if(regno<16) { + switch(current_par.bpp) { +#ifdef FBCON_HAS_CFB16 + case 16: + fbcon_cmap.cfb16[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + fbcon_cmap.cfb32[regno] = + ((red & 0xff00) << 8) | + ((green & 0xff00) ) | + ((blue & 0xff00) >> 8); + break; +#endif + } + } + + return 0; +} + +static int dcfb_blank(int blank_mode, const struct fb_info *info) +{ + return 0; +} + + +static void dcfb_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info) +{ + disp->screen_base = (void *)dc_videobase; + disp->scrollmode = SCROLL_YREDRAW; + + switch(((struct dcfb_par *)par)->bpp) { +#ifdef FBCON_HAS_CFB16 + case 16: + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = fbcon_cmap.cfb32; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + } +} + + +struct fbgen_hwswitch dcfb_switch = { + dcfb_detect, + dcfb_encode_fix, + dcfb_decode_var, + dcfb_encode_var, + dcfb_get_par, + dcfb_set_par, + dcfb_getcolreg, + dcfb_setcolreg, + NULL, + dcfb_blank, + dcfb_set_disp +}; + +static struct fb_ops dcfb_ops = { + owner: THIS_MODULE, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, +}; + + +int __init dcfb_init(void) +{ + strcpy(fb_info.gen.info.modename, "SEGA Dreamcast"); + fb_info.gen.info.node = -1; + fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; + fb_info.gen.info.fbops = &dcfb_ops; + fb_info.gen.info.disp = &disp; + fb_info.gen.info.changevar = NULL; + fb_info.gen.info.switch_con = &fbgen_switch; + fb_info.gen.info.updatevar = &fbgen_update_var; + fb_info.gen.info.blank = &fbgen_blank; + fb_info.gen.parsize = sizeof(struct dcfb_par); + fb_info.gen.fbhw = &dcfb_switch; + fb_info.gen.fbhw->detect(); + + fbgen_get_var(&disp.var, -1, &fb_info.gen.info); + disp.var.activate = FB_ACTIVATE_NOW; + fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_set_disp(-1, &fb_info.gen); + fbgen_install_cmap(0, &fb_info.gen); + + if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename); + + return 0; +} + + +void dcfb_cleanup(struct fb_info *info) +{ + unregister_framebuffer(info); +} + + +#ifdef MODULE +int init_module(void) +{ + return dcfb_init(); +} + +void cleanup_module(void) +{ + dcfb_cleanup(void); +} +#endif diff -u --recursive --new-file v2.4.3/linux/drivers/video/epson1355fb.c linux/drivers/video/epson1355fb.c --- v2.4.3/linux/drivers/video/epson1355fb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/epson1355fb.c Fri Apr 13 20:31:32 2001 @@ -0,0 +1,539 @@ +/* + * linux/drivers/video/epson1355fb.c + * -- Support for the Epson SED1355 LCD/CRT controller + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + * based on linux/drivers/video/skeletonfb.c, which was + * Created 28 Dec 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +/* TODO (roughly in order of priority): + * 16 bpp support + * crt support + * hw cursor support + * SwivelView + */ + +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/tty.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon.h> + +/* Register defines. The docs don't seem to provide nice mnemonic names + * so I made them up myself ... */ + +#define E1355_PANEL 0x02 +#define E1355_DISPLAY 0x0D +#define E1355_MISC 0x1B +#define E1355_GPIO 0x20 +#define E1355_LUT_INDEX 0x24 +#define E1355_LUT_DATA 0x26 + +#ifdef CONFIG_SUPERH +#define E1355_REG_BASE CONFIG_E1355_REG_BASE +#define E1355_FB_BASE CONFIG_E1355_FB_BASE + +static inline u8 e1355_read_reg(int index) +{ + return ctrl_inb(E1355_REG_BASE + index); +} + +static inline void e1355_write_reg(u8 data, int index) +{ + ctrl_outb(data, E1355_REG_BASE + index); +} + +static inline u16 e1355_read_reg16(int index) +{ + return e1355_read_reg(index) + (e1355_read_reg(index+1) << 8); +} + +static inline void e1355_write_reg16(u16 data, int index) +{ + e1355_write_reg((data&0xff), index); + e1355_write_reg(((data>>8)&0xff), index + 1); +} +#else +#error unknown architecture +#endif + +struct e1355fb_info { + struct fb_info_gen gen; +}; + +static int current_par_valid = 0; +static struct display disp; + +static struct fb_var_screeninfo default_var; + +int e1355fb_init(void); +int e1355fb_setup(char*); +static int e1355_encode_var(struct fb_var_screeninfo *var, const void *par, + struct fb_info_gen *info); +/* ------------------- chipset specific functions -------------------------- */ + + +static void disable_hw_cursor(void) +{ + u8 curs; + + curs = e1355_read_reg(0x27); + curs &= ~0xc0; + e1355_write_reg(curs, 0x27); +} + +static void e1355_detect(void) +{ + u8 rev; + + e1355_write_reg(0x00, E1355_MISC); + + rev = e1355_read_reg(0x00); + + if ((rev & 0xfc) != 0x0c) { + printk(KERN_WARNING "Epson 1355 not detected\n"); + } + + /* XXX */ + disable_hw_cursor(); + + e1355_encode_var(&default_var, NULL, NULL); +} + +struct e1355_par { + u32 xres; + u32 yres; + + int bpp; + int mem_bpp; + + u32 panel_xres; + u32 panel_yres; + + int panel_width; + int panel_ymul; +}; + +static int e1355_encode_fix(struct fb_fix_screeninfo *fix, + const void *raw_par, + struct fb_info_gen *info) +{ + const struct e1355_par *par = raw_par; + + memset(fix, 0, sizeof *fix); + + fix->type= FB_TYPE_PACKED_PIXELS; + + if (!par) + BUG(); + + if (par->bpp == 1) { + fix->visual = FB_VISUAL_MONO10; + } else if (par->bpp <= 8) { + fix->visual = FB_VISUAL_PSEUDOCOLOR; + } else { + fix->visual = FB_VISUAL_TRUECOLOR; + } + + return 0; +} + +static int e1355_set_bpp(struct e1355_par *par, int bpp) +{ + int code; + u8 disp; + u16 bytes_per_line; + + switch(bpp) { + case 1: + code = 0; break; + case 2: + code = 1; break; + case 4: + code = 2; break; + case 8: + code = 3; break; + case 16: + code = 5; break; + default: + return -EINVAL; break; + } + + disp = e1355_read_reg(E1355_DISPLAY); + disp &= ~0x1c; + disp |= code << 2; + e1355_write_reg(disp, E1355_DISPLAY); + + bytes_per_line = (par->xres * bpp) >> 3; + + e1355_write_reg16(bytes_per_line, 0x16); + + par->bpp = bpp; + + return 0; +} + +static int e1355_decode_var(const struct fb_var_screeninfo *var, + void *raw_par, + struct fb_info_gen *info) +{ + struct e1355_par *par = raw_par; + int ret; + + if (!par) + BUG(); + + /* + * Don't allow setting any of these yet: xres and yres don't + * make sense for LCD panels; xres_virtual and yres_virtual + * should be supported fine by our hardware though. + */ + if (var->xres != par->xres || + var->yres != par->yres || + var->xres != var->xres_virtual || + var->yres != var->yres_virtual || + var->xoffset != 0 || + var->yoffset != 0) + return -EINVAL; + + if(var->bits_per_pixel != par->bpp) { + ret = e1355_set_bpp(par, var->bits_per_pixel); + + if (ret) + goto out_err; + } + + return 0; + + out_err: + return ret; +} + +static void dump_panel_data(void) +{ + u8 panel = e1355_read_reg(E1355_PANEL); + int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } }; + + printk("%s %s %s panel, width %d bits\n", + panel & 2 ? "dual" : "single", + panel & 4 ? "color" : "mono", + panel & 1 ? "TFT" : "passive", + width[panel&1][(panel>>4)&3]); + + printk("resolution %d x %d\n", + (e1355_read_reg(0x04) + 1) * 8, + ((e1355_read_reg16(0x08) + 1) * (1 + ((panel & 3) == 2)))); +} + +static int e1355_bpp_to_var(int bpp, struct fb_var_screeninfo *var) +{ + switch(bpp) { + case 1: + case 2: + case 4: + case 8: + var->bits_per_pixel = bpp; + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = bpp; + break; + case 16: + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + + return 0; +} + +static int e1355_encode_var(struct fb_var_screeninfo *var, const void *raw_par, + struct fb_info_gen *info) +{ + u8 panel, display; + u32 xres, xres_virtual, yres; + static int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } }; + static int bpp_tab[8] = { 1, 2, 4, 8, 15, 16 }; + int bpp, hw_bpp; + int is_color, is_dual, is_tft; + int lcd_enabled, crt_enabled; + + panel = e1355_read_reg(E1355_PANEL); + display = e1355_read_reg(E1355_DISPLAY); + + is_color = (panel & 0x04) != 0; + is_dual = (panel & 0x02) != 0; + is_tft = (panel & 0x01) != 0; + + bpp = bpp_tab[(display>>2)&7]; + e1355_bpp_to_var(bpp, var); + + crt_enabled = (display & 0x02) != 0; + lcd_enabled = (display & 0x02) != 0; + + hw_bpp = width[is_tft][(panel>>4)&3]; + + xres = e1355_read_reg(0x04) + 1; + yres = e1355_read_reg16(0x08) + 1; + + xres *= 8; + /* talk about weird hardware .. */ + yres *= (is_dual && !crt_enabled) ? 2 : 1; + + xres_virtual = e1355_read_reg16(0x16); + /* it's in 2-byte words initially */ + xres_virtual *= 16; + xres_virtual /= var->bits_per_pixel; + + var->xres = xres; + var->yres = yres; + var->xres_virtual = xres_virtual; + var->yres_virtual = yres; + + var->xoffset = var->yoffset = 0; + + var->grayscale = !is_color; + + return 0; +} + +#define is_dual(panel) (((panel)&3)==2) + +static void get_panel_data(struct e1355_par *par) +{ + u8 panel; + int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } }; + + panel = e1355_read_reg(E1355_PANEL); + + par->panel_width = width[panel&1][(panel>>4)&3]; + par->panel_xres = (e1355_read_reg(0x04) + 1) * 8; + par->panel_ymul = is_dual(panel) ? 2 : 1; + par->panel_yres = ((e1355_read_reg16(0x08) + 1) + * par->panel_ymul); +} + +static void e1355_get_par(void *raw_par, struct fb_info_gen *info) +{ + struct e1355_par *par = raw_par; + + get_panel_data(par); +} + +static void e1355_set_par(const void *par, struct fb_info_gen *info) +{ +} + +static int e1355_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) +{ + u8 r, g, b; + + e1355_write_reg(regno, E1355_LUT_INDEX); + r = e1355_read_reg(E1355_LUT_DATA); + g = e1355_read_reg(E1355_LUT_DATA); + b = e1355_read_reg(E1355_LUT_DATA); + + *red = r << 8; + *green = g << 8; + *blue = b << 8; + + return 0; +} + +static int e1355_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u8 r = (red >> 8) & 0xf0; + u8 g = (green>>8) & 0xf0; + u8 b = (blue>> 8) & 0xf0; + + e1355_write_reg(regno, E1355_LUT_INDEX); + e1355_write_reg(r, E1355_LUT_DATA); + e1355_write_reg(g, E1355_LUT_DATA); + e1355_write_reg(b, E1355_LUT_DATA); + + return 0; +} + +static int e1355_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info) +{ + BUG(); + + return -EINVAL; +} + +/* + * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000. + * I'm not sure they aren't dangerous to the hardware, so be warned. + */ +#undef AERO_HACKS + +static int e1355_blank(int blank_mode, struct fb_info_gen *info) +{ + u8 disp; + + switch (blank_mode) { + case VESA_NO_BLANKING: + disp = e1355_read_reg(E1355_DISPLAY); + disp |= 1; + e1355_write_reg(disp, E1355_DISPLAY); + +#ifdef AERO_HACKS + e1355_write_reg(0x6, 0x20); +#endif + break; + + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + case VESA_POWERDOWN: + disp = e1355_read_reg(E1355_DISPLAY); + disp &= ~1; + e1355_write_reg(disp, E1355_DISPLAY); + +#ifdef AERO_HACKS + e1355_write_reg(0x0, 0x20); +#endif + break; + + default: + return -EINVAL; + } + + return 0; +} + +static struct display_switch e1355_dispsw; + +static void e1355_set_disp(const void *unused, struct display *disp, + struct fb_info_gen *info) +{ + struct display_switch *d; + + disp->screen_base = (void *)E1355_FB_BASE; + disp->dispsw = &e1355_dispsw; + + switch(disp->var.bits_per_pixel) { +#ifdef FBCON_HAS_MFB + case 1: + d = &fbcon_mfb; break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + d = &fbcon_cfb8; break; +#endif + default: + BUG(); break; + } + + memcpy(&e1355_dispsw, d, sizeof *d); + + /* reading is terribly slow for us */ +#if 0 /* XXX: need to work out why this doesn't work */ + e1355_dispsw.bmove = fbcon_redraw_bmove; +#endif +} + +/* ------------ Interfaces to hardware functions ------------ */ + + +struct fbgen_hwswitch e1355_switch = { + detect: e1355_detect, + encode_fix: e1355_encode_fix, + decode_var: e1355_decode_var, + encode_var: e1355_encode_var, + get_par: e1355_get_par, + set_par: e1355_set_par, + getcolreg: e1355_getcolreg, + setcolreg: e1355_setcolreg, + pan_display: e1355_pan_display, + blank: e1355_blank, + set_disp: e1355_set_disp, +}; + + +/* ------------ Hardware Independent Functions ------------ */ + + +static struct fb_ops e1355fb_ops = { + owner: THIS_MODULE, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_pan_display: fbgen_pan_display, +}; + +static struct e1355fb_info fb_info; + +int __init e1355fb_setup(char *str) +{ + return 0; +} + +int __init e1355fb_init(void) +{ + fb_info.gen.fbhw = &e1355_switch; + fb_info.gen.fbhw->detect(); + strcpy(fb_info.gen.info.modename, "SED1355"); + fb_info.gen.info.changevar = NULL; + fb_info.gen.info.node = -1; + fb_info.gen.info.fbops = &e1355fb_ops; + fb_info.gen.info.disp = &disp; + fb_info.gen.parsize = sizeof(struct e1355_par); + fb_info.gen.info.switch_con = &fbgen_switch; + fb_info.gen.info.updatevar = &fbgen_update_var; + fb_info.gen.info.blank = &fbgen_blank; + fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; + /* This should give a reasonable default video mode */ + fbgen_get_var(&disp.var, -1, &fb_info.gen.info); + fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_set_disp(-1, &fb_info.gen); + if (disp.var.bits_per_pixel > 1) + fbgen_install_cmap(0, &fb_info.gen); + if (register_framebuffer(&fb_info.gen.info) < 0) + return -EINVAL; + printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node), + fb_info.gen.info.modename); + + return 0; +} + + + /* + * Cleanup + */ + +void e1355fb_cleanup(struct fb_info *info) +{ + /* + * If your driver supports multiple boards, you should unregister and + * clean up all instances. + */ + + unregister_framebuffer(info); + /* ... */ +} + diff -u --recursive --new-file v2.4.3/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.4.3/linux/drivers/video/fbmem.c Fri Mar 2 18:38:39 2001 +++ linux/drivers/video/fbmem.c Fri Apr 13 20:31:32 2001 @@ -120,7 +120,10 @@ extern int stifb_setup(char*); extern int radeonfb_init(void); extern int radeonfb_setup(char*); - +extern int e1355fb_init(void); +extern int e1355fb_setup(char*); +extern int dcfb_init(void); + static struct { const char *name; int (*init)(void); @@ -199,6 +202,9 @@ #ifdef CONFIG_FB_SIS { "sisfb", sisfb_init, sisfb_setup }, #endif +#ifdef CONFIG_FB_E1355 + { "e1355fb", e1355fb_init, e1355fb_setup }, +#endif /* * Generic drivers that are used as fallbacks @@ -264,6 +270,9 @@ #ifdef CONFIG_FB_HIT { "hitfb", hitfb_init, NULL }, #endif +#ifdef CONFIG_FB_DC + { "dcfb", dcfb_init, NULL }, +#endif /* * Generic drivers that don't use resource management (yet) @@ -562,22 +571,6 @@ vma->vm_pgoff = off >> PAGE_SHIFT; #if defined(__sparc_v9__) vma->vm_flags |= (VM_SHM | VM_LOCKED); - { - unsigned long align, j; - for (align = 0x400000; align > PAGE_SIZE; align >>= 3) - if (len >= align && !((start & ~PAGE_MASK) & (align - 1))) - break; - if (align > PAGE_SIZE && vma->vm_start & (align - 1)) { - /* align as much as possible */ - struct vm_area_struct *vmm; - j = (-vma->vm_start) & (align - 1); - vmm = find_vma(current->mm, vma->vm_start); - if (!vmm || vmm->vm_start >= vma->vm_end + j) { - vma->vm_start += j; - vma->vm_end += j; - } - } - } if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot, 0)) return -EAGAIN; @@ -687,6 +680,9 @@ mmap: fb_mmap, open: fb_open, release: fb_release, +#ifdef HAVE_ARCH_FB_UNMAPPED_AREA + get_unmapped_area: get_fb_unmapped_area, +#endif }; static devfs_handle_t devfs_handle; diff -u --recursive --new-file v2.4.3/linux/drivers/video/hitfb.c linux/drivers/video/hitfb.c --- v2.4.3/linux/drivers/video/hitfb.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/video/hitfb.c Wed Apr 11 21:24:52 2001 @@ -22,9 +22,11 @@ #include <linux/nubus.h> #include <linux/init.h> +#include <asm/machvec.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> +#include <asm/hd64461.h> #include <linux/fb.h> @@ -32,20 +34,6 @@ #include <video/fbcon-cfb8.h> #include <video/fbcon-cfb16.h> -#include <asm/hd64461.h> - -#define CONFIG_SH_LCD_VIDEOBASE CONFIG_HD64461_IOBASE+0x2000000 - -/* These are for HP Jornada 680/690. - It is desired that they are configurable... */ -#define CONFIG_SH_LCD_VIDEOSIZE 1024*1024 -#define CONFIG_SH_LCD_HORZ 640 -#define CONFIG_SH_LCD_VERT 240 -#define CONFIG_SH_LCD_DEFAULTBPP 16 - -struct hitfb_info { - struct fb_info_gen gen; -}; struct hitfb_par { @@ -53,55 +41,79 @@ int bpp; }; -static struct hitfb_info fb_info; -static struct hitfb_par current_par; -static int current_par_valid = 0; -static struct display disp; -static union { +struct hitfb_info { + struct fb_info_gen gen; + struct display disp; + struct hitfb_par current_par; + struct fb_var_screeninfo default_var; + int current_par_valid; + unsigned long hit_videobase, hit_videosize; + union { #ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; + u16 cfb16[16]; #endif -} fbcon_cmap; - -unsigned long hit_videobase, hit_videosize; -static struct fb_var_screeninfo default_var; + } fbcon_cmap; +} fb_info = { + {}, + {}, + {}, + {}, + 0, 0, 0, + {}, +}; -int hitfb_init(void); -static void hitfb_set_par(struct hitfb_par *par, const struct fb_info *info); -static void hitfb_encode_var(struct fb_var_screeninfo *var, - struct hitfb_par *par, - const struct fb_info *info); +static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info); +static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, + struct fb_info_gen *info); static void hitfb_detect(void) { struct hitfb_par par; + unsigned short lcdclor, ldr3, ldvntr; + + fb_info.hit_videobase = CONFIG_HD64461_IOBASE + 0x02000000; + fb_info.hit_videosize = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024; - hit_videobase = CONFIG_SH_LCD_VIDEOBASE; - hit_videosize = CONFIG_SH_LCD_VIDEOSIZE; + lcdclor = inw(HD64461_LCDCLOR); + ldvntr = inw(HD64461_LDVNTR); + ldr3 = inw(HD64461_LDR3); + + switch(ldr3&15) { + default: + case 4: + par.bpp = 8; + par.x = lcdclor; + break; + case 8: + par.bpp = 16; + par.x = lcdclor/2; + break; + } - par.x = CONFIG_SH_LCD_HORZ; - par.y = CONFIG_SH_LCD_VERT; - par.bpp = CONFIG_SH_LCD_DEFAULTBPP; + par.y = ldvntr+1; hitfb_set_par(&par, NULL); - hitfb_encode_var(&default_var, &par, NULL); + hitfb_encode_var(&fb_info.default_var, &par, NULL); } -static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, - struct hitfb_par *par, - const struct fb_info *info) + +static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par, + struct fb_info_gen *info) { + const struct hitfb_par *par = fb_par; + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "Hitachi HD64461"); - fix->smem_start = hit_videobase; - fix->smem_len = hit_videosize; + fix->smem_start = fb_info.hit_videobase; + fix->smem_len = fb_info.hit_videosize; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - fix->visual = FB_VISUAL_TRUECOLOR; + fix->visual = (par->bpp == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = 0; fix->ypanstep = 0; fix->ywrapstep = 0; @@ -120,10 +132,11 @@ } -static int hitfb_decode_var(struct fb_var_screeninfo *var, - struct hitfb_par *par, - const struct fb_info *info) +static int hitfb_decode_var(const struct fb_var_screeninfo *var, void *fb_par, + struct fb_info_gen *info) { + struct hitfb_par *par = fb_par; + par->x = var->xres; par->y = var->yres; par->bpp = var->bits_per_pixel; @@ -131,10 +144,11 @@ } -static void hitfb_encode_var(struct fb_var_screeninfo *var, - struct hitfb_par *par, - const struct fb_info *info) +static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, + struct fb_info_gen *info) { + const struct hitfb_par *par = fb_par; + memset(var, 0, sizeof(*var)); var->xres = par->x; @@ -191,25 +205,28 @@ var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; + + return 0; } -static void hitfb_get_par(struct hitfb_par *par, const struct fb_info *info) +static void hitfb_get_par(void *par, struct fb_info_gen *info) { - *par = current_par; + *(struct hitfb_par *)par = fb_info.current_par; } -static void hitfb_set_par(struct hitfb_par *par, const struct fb_info *info) +static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info) { - /* Set the hardware according to 'par'. */ - current_par = *par; - current_par_valid = 1; + const struct hitfb_par *par = fb_par; + fb_info.current_par = *par; + fb_info.current_par_valid = 1; } -static int hitfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) +static int hitfb_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) { if (regno > 255) return 1; @@ -224,8 +241,9 @@ } -static int hitfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { if (regno > 255) return 1; @@ -236,10 +254,10 @@ outw(blue>>10, HD64461_CPTWDR); if(regno<16) { - switch(current_par.bpp) { + switch(fb_info.current_par.bpp) { #ifdef FBCON_HAS_CFB16 case 16: - fbcon_cmap.cfb16[regno] = + fb_info.fbcon_cmap.cfb16[regno] = ((red & 0xf800) ) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); @@ -251,16 +269,34 @@ return 0; } -static int hitfb_blank(int blank_mode, const struct fb_info *info) + +static int hitfb_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info) { + if (!fb_info.current_par_valid) + return -EINVAL; + return 0; } -static void hitfb_set_disp(const void *par, struct display *disp, - struct fb_info_gen *info) +static int hitfb_blank(int blank_mode, struct fb_info_gen *info) { - disp->screen_base = (void *)hit_videobase; + if (!fb_info.current_par_valid) + return 1; + + return 0; +} + + +static void hitfb_set_disp(const void *fb_par, struct display *disp, + struct fb_info_gen *info) +{ + const struct hitfb_par *par = fb_par; + + disp->screen_base = (void *)fb_info.hit_videobase; + disp->scrollmode = SCROLL_YREDRAW; + switch(((struct hitfb_par *)par)->bpp) { #ifdef FBCON_HAS_CFB8 case 8: @@ -270,7 +306,7 @@ #ifdef FBCON_HAS_CFB16 case 16: disp->dispsw = &fbcon_cfb16; - disp->dispsw_data = fbcon_cmap.cfb16; + disp->dispsw_data = fb_info.fbcon_cmap.cfb16; break; #endif default: @@ -288,18 +324,20 @@ hitfb_set_par, hitfb_getcolreg, hitfb_setcolreg, - NULL, + hitfb_pan_display, hitfb_blank, hitfb_set_disp }; + static struct fb_ops hitfb_ops = { - owner: THIS_MODULE, - fb_get_fix: fbgen_get_fix, - fb_get_var: fbgen_get_var, - fb_set_var: fbgen_set_var, - fb_get_cmap: fbgen_get_cmap, - fb_set_cmap: fbgen_set_cmap, + owner: THIS_MODULE, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_pan_display: fbgen_pan_display, }; @@ -309,7 +347,7 @@ fb_info.gen.info.node = -1; fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; fb_info.gen.info.fbops = &hitfb_ops; - fb_info.gen.info.disp = &disp; + fb_info.gen.info.disp = &fb_info.disp; fb_info.gen.info.changevar = NULL; fb_info.gen.info.switch_con = &fbgen_switch; fb_info.gen.info.updatevar = &fbgen_update_var; @@ -318,9 +356,9 @@ fb_info.gen.fbhw = &hitfb_switch; fb_info.gen.fbhw->detect(); - fbgen_get_var(&disp.var, -1, &fb_info.gen.info); - disp.var.activate = FB_ACTIVATE_NOW; - fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info); + fb_info.disp.var.activate = FB_ACTIVATE_NOW; + fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen); fbgen_set_disp(-1, &fb_info.gen); fbgen_install_cmap(0, &fb_info.gen); @@ -347,6 +385,13 @@ void cleanup_module(void) { - hitfb_cleanup(void); + hitfb_cleanup(void); } #endif + + +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ diff -u --recursive --new-file v2.4.3/linux/drivers/video/matrox/matroxfb_DAC1064.c linux/drivers/video/matrox/matroxfb_DAC1064.c --- v2.4.3/linux/drivers/video/matrox/matroxfb_DAC1064.c Sun Feb 4 10:05:30 2001 +++ linux/drivers/video/matrox/matroxfb_DAC1064.c Wed Apr 11 19:21:35 2001 @@ -416,7 +416,12 @@ outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); - if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) { + /* + * We must ALWAYS reprogram hardware due to broken XF4 matrox drivers... + * + * if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) + */ + { unsigned int i; for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { diff -u --recursive --new-file v2.4.3/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c --- v2.4.3/linux/drivers/video/sbusfb.c Sun Mar 25 18:14:20 2001 +++ linux/drivers/video/sbusfb.c Thu Apr 12 12:10:25 2001 @@ -193,44 +193,6 @@ /* To stop the swapper from even considering these pages */ vma->vm_flags |= (VM_SHM| VM_LOCKED); -#ifdef __sparc_v9__ - /* Align it as much as desirable */ - { - unsigned long j, alignment, s = 0; - int max = -1; - - map_offset = (vma->vm_pgoff << PAGE_SHIFT) + size; - for (i = 0; fb->mmap_map[i].size; i++) { - if (fb->mmap_map[i].voff < off) - continue; - if (fb->mmap_map[i].voff >= map_offset) - break; - if (max < 0 || sbusfb_mmapsize(fb,fb->mmap_map[i].size) > s) { - max = i; - s = sbusfb_mmapsize(fb,fb->mmap_map[max].size); - } - } - if (max >= 0) { - j = s; - if (fb->mmap_map[max].voff + j > map_offset) - j = map_offset - fb->mmap_map[max].voff; - for (alignment = 0x400000; alignment > PAGE_SIZE; alignment >>= 3) - if (j >= alignment && !(fb->mmap_map[max].poff & (alignment - 1))) - break; - if (alignment > PAGE_SIZE) { - j = alignment; - alignment = j - ((vma->vm_start + fb->mmap_map[max].voff - off) & (j - 1)); - if (alignment != j) { - struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start); - if (!vmm || vmm->vm_start >= vma->vm_end + alignment) { - vma->vm_start += alignment; - vma->vm_end += alignment; - } - } - } - } - } -#endif /* Each page, see which map applies */ for (page = 0; page < size; ){ diff -u --recursive --new-file v2.4.3/linux/fs/Config.in linux/fs/Config.in --- v2.4.3/linux/fs/Config.in Mon Jan 15 12:42:32 2001 +++ linux/fs/Config.in Thu Apr 12 12:25:53 2001 @@ -31,6 +31,7 @@ int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0 fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS +bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS tristate 'Simple RAM-based file system support' CONFIG_RAMFS tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS diff -u --recursive --new-file v2.4.3/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.4.3/linux/fs/binfmt_elf.c Mon Mar 19 17:05:16 2001 +++ linux/fs/binfmt_elf.c Thu Apr 5 17:13:23 2001 @@ -140,7 +140,7 @@ */ sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL); csp = sp; - csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0)); + csp -= DLINFO_ITEMS*2 + (k_platform ? 2 : 0); csp -= envc+1; csp -= argc+1; csp -= (!ibcs ? 3 : 1); /* argc itself */ @@ -160,25 +160,20 @@ sp -= 2; NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform); } - sp -= 3*2; - NEW_AUX_ENT(0, AT_HWCAP, hwcap); - NEW_AUX_ENT(1, AT_PAGESZ, ELF_EXEC_PAGESIZE); - NEW_AUX_ENT(2, AT_CLKTCK, CLOCKS_PER_SEC); - - if (exec) { - sp -= 10*2; - - NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff); - NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT(3, AT_BASE, interp_load_addr); - NEW_AUX_ENT(4, AT_FLAGS, 0); - NEW_AUX_ENT(5, AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT(6, AT_UID, (elf_addr_t) current->uid); - NEW_AUX_ENT(7, AT_EUID, (elf_addr_t) current->euid); - NEW_AUX_ENT(8, AT_GID, (elf_addr_t) current->gid); - NEW_AUX_ENT(9, AT_EGID, (elf_addr_t) current->egid); - } + sp -= DLINFO_ITEMS*2; + NEW_AUX_ENT( 0, AT_HWCAP, hwcap); + NEW_AUX_ENT( 1, AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC); + NEW_AUX_ENT( 3, AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT( 4, AT_PHENT, sizeof (struct elf_phdr)); + NEW_AUX_ENT( 5, AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT( 6, AT_BASE, interp_load_addr); + NEW_AUX_ENT( 7, AT_FLAGS, 0); + NEW_AUX_ENT( 8, AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid); + NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid); + NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid); + NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid); #undef NEW_AUX_ENT sp -= envc+1; @@ -694,7 +689,7 @@ create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, - (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + &elf_ex, load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); diff -u --recursive --new-file v2.4.3/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.3/linux/fs/buffer.c Sat Mar 24 19:31:58 2001 +++ linux/fs/buffer.c Thu Apr 12 12:10:25 2001 @@ -1367,11 +1367,12 @@ { if (buffer_mapped(bh)) { mark_buffer_clean(bh); - wait_on_buffer(bh); + lock_buffer(bh); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Mapped, &bh->b_state); clear_bit(BH_Req, &bh->b_state); clear_bit(BH_New, &bh->b_state); + unlock_buffer(bh); } } diff -u --recursive --new-file v2.4.3/linux/fs/coda/dir.c linux/fs/coda/dir.c --- v2.4.3/linux/fs/coda/dir.c Fri Dec 29 14:07:57 2000 +++ linux/fs/coda/dir.c Fri Apr 6 10:51:19 2001 @@ -92,7 +92,7 @@ /* inode operations for directories */ -/* acces routines: lookup, readlink, permission */ +/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) { struct inode *res_inode = NULL; diff -u --recursive --new-file v2.4.3/linux/fs/coda/psdev.c linux/fs/coda/psdev.c --- v2.4.3/linux/fs/coda/psdev.c Fri Feb 9 11:29:44 2001 +++ linux/fs/coda/psdev.c Fri Apr 6 10:51:19 2001 @@ -195,7 +195,7 @@ goto out; } - /* adjust outsize. is this usefull ?? */ + /* adjust outsize. is this useful ?? */ req->uc_outSize = nbytes; req->uc_flags |= REQ_WRITE; count = nbytes; diff -u --recursive --new-file v2.4.3/linux/fs/dcache.c linux/fs/dcache.c --- v2.4.3/linux/fs/dcache.c Wed Mar 7 16:53:48 2001 +++ linux/fs/dcache.c Thu Apr 12 12:14:45 2001 @@ -340,7 +340,7 @@ if (dentry->d_flags & DCACHE_REFERENCED) { dentry->d_flags &= ~DCACHE_REFERENCED; list_add(&dentry->d_lru, &dentry_unused); - goto next; + continue; } dentry_stat.nr_unused--; @@ -349,7 +349,6 @@ BUG(); prune_one_dentry(dentry); - next: if (!--count) break; } diff -u --recursive --new-file v2.4.3/linux/fs/devfs/base.c linux/fs/devfs/base.c --- v2.4.3/linux/fs/devfs/base.c Fri Feb 9 11:29:44 2001 +++ linux/fs/devfs/base.c Tue Apr 17 15:04:10 2001 @@ -3339,7 +3339,7 @@ } /* End Function devfsd_close */ -int __init init_devfs_fs (void) +static int __init init_devfs_fs (void) { int err; @@ -3369,3 +3369,5 @@ if (err == 0) printk ("Mounted devfs on /dev\n"); else printk ("Warning: unable to mount devfs, err: %d\n", err); } /* End Function mount_devfs_fs */ + +module_init(init_devfs_fs) diff -u --recursive --new-file v2.4.3/linux/fs/devpts/inode.c linux/fs/devpts/inode.c --- v2.4.3/linux/fs/devpts/inode.c Fri Feb 9 11:29:44 2001 +++ linux/fs/devpts/inode.c Tue Apr 17 15:04:36 2001 @@ -220,7 +220,7 @@ } } -int __init init_devpts_fs(void) +static int __init init_devpts_fs(void) { int err = register_filesystem(&devpts_fs_type); if (!err) { @@ -228,28 +228,25 @@ err = PTR_ERR(devpts_mnt); if (!IS_ERR(devpts_mnt)) err = 0; - } - return err; -} - #ifdef MODULE - -int init_module(void) -{ - int err = init_devpts_fs(); - if ( !err ) { - devpts_upcall_new = devpts_pty_new; - devpts_upcall_kill = devpts_pty_kill; + if ( !err ) { + devpts_upcall_new = devpts_pty_new; + devpts_upcall_kill = devpts_pty_kill; + } +#endif } return err; } -void cleanup_module(void) +static void __exit exit_devpts_fs(void) { +#ifdef MODULE devpts_upcall_new = NULL; devpts_upcall_kill = NULL; +#endif unregister_filesystem(&devpts_fs_type); kern_umount(devpts_mnt); } -#endif +module_init(init_devpts_fs) +module_exit(exit_devpts_fs) diff -u --recursive --new-file v2.4.3/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.4.3/linux/fs/ext2/inode.c Fri Mar 23 12:15:29 2001 +++ linux/fs/ext2/inode.c Tue Apr 10 12:10:43 2001 @@ -568,7 +568,7 @@ changed: while (partial > chain) { - bforget(partial->bh); + brelse(partial->bh); partial--; } goto reread; @@ -799,8 +799,8 @@ /* Writer: ->i_blocks */ inode->i_blocks -= blocks * count; /* Writer: end */ - ext2_free_blocks (inode, block_to_free, count); mark_inode_dirty(inode); + ext2_free_blocks (inode, block_to_free, count); free_this: block_to_free = nr; count = 1; @@ -811,8 +811,8 @@ /* Writer: ->i_blocks */ inode->i_blocks -= blocks * count; /* Writer: end */ - ext2_free_blocks (inode, block_to_free, count); mark_inode_dirty(inode); + ext2_free_blocks (inode, block_to_free, count); } } diff -u --recursive --new-file v2.4.3/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.4.3/linux/fs/filesystems.c Mon Sep 25 17:05:01 2000 +++ linux/fs/filesystems.c Tue Apr 17 15:04:10 2001 @@ -7,36 +7,10 @@ */ #include <linux/config.h> -#include <linux/fs.h> - -#include <linux/devfs_fs_kernel.h> -#include <linux/nfs_fs.h> -#include <linux/auto_fs.h> -#include <linux/devpts_fs.h> -#include <linux/major.h> -#include <linux/smp.h> +#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/kmod.h> -#include <linux/init.h> -#include <linux/module.h> #include <linux/nfsd/interface.h> - -#ifdef CONFIG_DEVPTS_FS -extern int init_devpts_fs(void); -#endif - -void __init filesystem_setup(void) -{ - init_devfs_fs(); /* Header file may make this empty */ - -#ifdef CONFIG_NFS_FS - init_nfs_fs(); -#endif - -#ifdef CONFIG_DEVPTS_FS - init_devpts_fs(); -#endif -} #if defined(CONFIG_NFSD_MODULE) struct nfsd_linkage *nfsd_linkage = NULL; diff -u --recursive --new-file v2.4.3/linux/fs/minix/itree_common.c linux/fs/minix/itree_common.c --- v2.4.3/linux/fs/minix/itree_common.c Wed Sep 27 19:23:40 2000 +++ linux/fs/minix/itree_common.c Sun Apr 8 12:30:59 2001 @@ -201,7 +201,7 @@ changed: while (partial > chain) { - bforget(partial->bh); + brelse(partial->bh); partial--; } goto reread; diff -u --recursive --new-file v2.4.3/linux/fs/nfs/flushd.c linux/fs/nfs/flushd.c --- v2.4.3/linux/fs/nfs/flushd.c Fri Feb 9 11:29:44 2001 +++ linux/fs/nfs/flushd.c Tue Apr 3 13:45:37 2001 @@ -177,14 +177,14 @@ out: } +/* Protect me using the BKL */ void inode_remove_flushd(struct inode *inode) { struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct inode **q; - lock_kernel(); if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH)) - goto out; + return; q = &cache->inodes; while (*q && *q != inode) @@ -194,8 +194,6 @@ NFS_FLAGS(inode) &= ~NFS_INO_FLUSH; iput(inode); } - out: - unlock_kernel(); } void inode_schedule_scan(struct inode *inode, unsigned long time) diff -u --recursive --new-file v2.4.3/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.4.3/linux/fs/nfs/inode.c Fri Mar 2 11:12:11 2001 +++ linux/fs/nfs/inode.c Tue Apr 17 15:04:11 2001 @@ -15,6 +15,7 @@ #include <linux/config.h> #include <linux/module.h> +#include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -1060,8 +1061,7 @@ /* * Initialize NFS */ -int -init_nfs_fs(void) +static int __init init_nfs_fs(void) { int err; @@ -1079,23 +1079,7 @@ return register_filesystem(&nfs_fs_type); } -/* - * Every kernel module contains stuff like this. - */ -#ifdef MODULE - -EXPORT_NO_SYMBOLS; -/* Not quite true; I just maintain it */ -MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); - -int -init_module(void) -{ - return init_nfs_fs(); -} - -void -cleanup_module(void) +static void __exit exit_nfs_fs(void) { nfs_destroy_readpagecache(); nfs_destroy_nfspagecache(); @@ -1104,4 +1088,10 @@ #endif unregister_filesystem(&nfs_fs_type); } -#endif + +EXPORT_NO_SYMBOLS; +/* Not quite true; I just maintain it */ +MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); + +module_init(init_nfs_fs) +module_exit(exit_nfs_fs) diff -u --recursive --new-file v2.4.3/linux/fs/nfs/read.c linux/fs/nfs/read.c --- v2.4.3/linux/fs/nfs/read.c Fri Feb 9 11:29:44 2001 +++ linux/fs/nfs/read.c Tue Apr 3 13:45:37 2001 @@ -335,7 +335,9 @@ rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); + lock_kernel(); rpc_execute(task); + unlock_kernel(); rpc_clnt_sigunmask(clnt, &oldset); return 0; out_bad: diff -u --recursive --new-file v2.4.3/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.4.3/linux/fs/nfs/write.c Fri Feb 9 11:29:44 2001 +++ linux/fs/nfs/write.c Tue Apr 3 13:45:37 2001 @@ -183,7 +183,6 @@ if (file) cred = nfs_file_cred(file); - lock_kernel(); dprintk("NFS: nfs_writepage_sync(%x/%Ld %d@%Ld)\n", inode->i_dev, (long long)NFS_FILEID(inode), count, (long long)(page_offset(page) + offset)); @@ -228,7 +227,6 @@ io_error: kunmap(page); - unlock_kernel(); return written? written : result; } @@ -282,16 +280,17 @@ if (page->index >= end_index+1 || !offset) goto out; do_it: - if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { + lock_kernel(); + if (NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { err = nfs_writepage_async(NULL, inode, page, 0, offset); if (err >= 0) - goto out_ok; - } - err = nfs_writepage_sync(NULL, inode, page, 0, offset); - if ( err == offset) { -out_ok: - err = 0; + err = 0; + } else { + err = nfs_writepage_sync(NULL, inode, page, 0, offset); + if (err == offset) + err = 0; } + unlock_kernel(); out: UnlockPage(page); return err; @@ -1172,7 +1171,9 @@ rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); + lock_kernel(); rpc_execute(task); + unlock_kernel(); rpc_clnt_sigunmask(clnt, &oldset); return 0; out_bad: @@ -1394,7 +1395,9 @@ dprintk("NFS: %4d initiated commit call\n", task->tk_pid); rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); + lock_kernel(); rpc_execute(task); + unlock_kernel(); rpc_clnt_sigunmask(clnt, &oldset); return 0; out_bad: diff -u --recursive --new-file v2.4.3/linux/fs/nls/Config.in linux/fs/nls/Config.in --- v2.4.3/linux/fs/nls/Config.in Fri Dec 29 14:35:47 2000 +++ linux/fs/nls/Config.in Fri Apr 6 10:51:19 2001 @@ -37,23 +37,26 @@ tristate 'Codepage 865 (Norwegian, Danish)' CONFIG_NLS_CODEPAGE_865 tristate 'Codepage 866 (Cyrillic/Russian)' CONFIG_NLS_CODEPAGE_866 tristate 'Codepage 869 (Greek)' CONFIG_NLS_CODEPAGE_869 - tristate 'Codepage 874 (Thai)' CONFIG_NLS_CODEPAGE_874 - tristate 'Codepage 932 (Shift-JIS, EUC-JP)' CONFIG_NLS_CODEPAGE_932 - tristate 'Codepage 936 (GBK)' CONFIG_NLS_CODEPAGE_936 - tristate 'Codepage 949 (UnifiedHangul)' CONFIG_NLS_CODEPAGE_949 - tristate 'Codepage 950 (Big5)' CONFIG_NLS_CODEPAGE_950 + tristate 'Simplified Chinese charset (CP936, GB2312)' CONFIG_NLS_CODEPAGE_936 + tristate 'Traditional Chinese charset (Big5)' CONFIG_NLS_CODEPAGE_950 + tristate 'Japanese charsets (Shift-JIS, EUC-JP)' CONFIG_NLS_CODEPAGE_932 + tristate 'Korean charset (CP949, EUC-KR)' CONFIG_NLS_CODEPAGE_949 + tristate 'Thai charset (CP874, TIS-620)' CONFIG_NLS_CODEPAGE_874 + tristate 'Hebrew charsets (ISO-8859-8, CP1255)' CONFIG_NLS_ISO8859_8 + tristate 'Windows CP1251 (Bulgarian, Belarussian)' CONFIG_NLS_CODEPAGE_1251 tristate 'NLS ISO 8859-1 (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1 tristate 'NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2 tristate 'NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3 - tristate 'NLS ISO 8859-4 (Latin 4; Estonian, Latvian, Lithuanian)' CONFIG_NLS_ISO8859_4 + tristate 'NLS ISO 8859-4 (Latin 4; old Baltic charset)' CONFIG_NLS_ISO8859_4 tristate 'NLS ISO 8859-5 (Cyrillic)' CONFIG_NLS_ISO8859_5 tristate 'NLS ISO 8859-6 (Arabic)' CONFIG_NLS_ISO8859_6 tristate 'NLS ISO 8859-7 (Modern Greek)' CONFIG_NLS_ISO8859_7 - tristate 'NLS ISO 8859-8 (Hebrew)' CONFIG_NLS_ISO8859_8 tristate 'NLS ISO 8859-9 (Latin 5; Turkish)' CONFIG_NLS_ISO8859_9 + tristate 'NLS ISO 8859-13 (Latin 7; Baltic)' CONFIG_NLS_ISO8859_13 tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14 tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15 tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R + tristate 'NLS KOI8-U (Ukrainian)' CONFIG_NLS_KOI8_U tristate 'NLS UTF8' CONFIG_NLS_UTF8 endmenu fi diff -u --recursive --new-file v2.4.3/linux/fs/nls/Makefile linux/fs/nls/Makefile --- v2.4.3/linux/fs/nls/Makefile Fri Dec 29 14:07:23 2000 +++ linux/fs/nls/Makefile Fri Apr 6 10:51:19 2001 @@ -22,7 +22,7 @@ obj-$(CONFIG_NLS_CODEPAGE_865) += nls_cp865.o obj-$(CONFIG_NLS_CODEPAGE_866) += nls_cp866.o obj-$(CONFIG_NLS_CODEPAGE_869) += nls_cp869.o -obj-$(CONFIG_NLS_CODEPAGE_874) += nls_cp874.o +obj-$(CONFIG_NLS_CODEPAGE_874) += nls_cp874.o nls_tis-620.o obj-$(CONFIG_NLS_CODEPAGE_932) += nls_cp932.o nls_sjis.o nls_euc-jp.o obj-$(CONFIG_NLS_CODEPAGE_936) += nls_cp936.o nls_gb2312.o obj-$(CONFIG_NLS_CODEPAGE_949) += nls_cp949.o nls_euc-kr.o @@ -32,7 +32,6 @@ obj-$(CONFIG_NLS_CODEPAGE_1252) += nls_cp1252.o obj-$(CONFIG_NLS_CODEPAGE_1253) += nls_cp1253.o obj-$(CONFIG_NLS_CODEPAGE_1254) += nls_cp1254.o -obj-$(CONFIG_NLS_CODEPAGE_1255) += nls_cp1255.o obj-$(CONFIG_NLS_CODEPAGE_1256) += nls_cp1256.o obj-$(CONFIG_NLS_CODEPAGE_1257) += nls_cp1257.o obj-$(CONFIG_NLS_CODEPAGE_1258) += nls_cp1258.o @@ -43,12 +42,14 @@ obj-$(CONFIG_NLS_ISO8859_5) += nls_iso8859-5.o obj-$(CONFIG_NLS_ISO8859_6) += nls_iso8859-6.o obj-$(CONFIG_NLS_ISO8859_7) += nls_iso8859-7.o -obj-$(CONFIG_NLS_ISO8859_8) += nls_iso8859-8.o +obj-$(CONFIG_NLS_ISO8859_8) += nls_cp1255.o nls_iso8859-8.o obj-$(CONFIG_NLS_ISO8859_9) += nls_iso8859-9.o obj-$(CONFIG_NLS_ISO8859_10) += nls_iso8859-10.o +obj-$(CONFIG_NLS_ISO8859_13) += nls_iso8859-13.o obj-$(CONFIG_NLS_ISO8859_14) += nls_iso8859-14.o obj-$(CONFIG_NLS_ISO8859_15) += nls_iso8859-15.o obj-$(CONFIG_NLS_KOI8_R) += nls_koi8-r.o +obj-$(CONFIG_NLS_KOI8_U) += nls_koi8-u.o obj-$(CONFIG_NLS_ABC) += nls_abc.o obj-$(CONFIG_NLS_UTF8) += nls_utf8.o diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_cp1251.c linux/fs/nls/nls_cp1251.c --- v2.4.3/linux/fs/nls/nls_cp1251.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nls/nls_cp1251.c Fri Apr 6 10:51:19 2001 @@ -0,0 +1,317 @@ +/* + * linux/fs/nls_cp1251.c + * + * Charset cp1251 translation tables. + * Generated automatically from the Unicode and charset + * tables from the Unicode Organization (www.unicode.org). + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x0402, 0x0403, 0x201a, 0x0453, + 0x201e, 0x2026, 0x2020, 0x2021, + 0x20ac, 0x2030, 0x0409, 0x2039, + 0x040a, 0x040c, 0x040b, 0x040f, + /* 0x90*/ + 0x0452, 0x2018, 0x2019, 0x201c, + 0x201d, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0459, 0x203a, + 0x045a, 0x045c, 0x045b, 0x045f, + /* 0xa0*/ + 0x00a0, 0x040e, 0x045e, 0x0408, + 0x00a4, 0x0490, 0x00a6, 0x00a7, + 0x0401, 0x00a9, 0x0404, 0x00ab, + 0x00ac, 0x00ad, 0x00ae, 0x0407, + /* 0xb0*/ + 0x00b0, 0x00b1, 0x0406, 0x0456, + 0x0491, 0x00b5, 0x00b6, 0x00b7, + 0x0451, 0x2116, 0x0454, 0x00bb, + 0x0458, 0x0405, 0x0455, 0x0457, + /* 0xc0*/ + 0x0410, 0x0411, 0x0412, 0x0413, + 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041a, 0x041b, + 0x041c, 0x041d, 0x041e, 0x041f, + /* 0xd0*/ + 0x0420, 0x0421, 0x0422, 0x0423, + 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, + 0x042c, 0x042d, 0x042e, 0x042f, + /* 0xe0*/ + 0x0430, 0x0431, 0x0432, 0x0433, + 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, + 0x043c, 0x043d, 0x043e, 0x043f, + /* 0xf0*/ + 0x0440, 0x0441, 0x0442, 0x0443, + 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, + 0x044c, 0x044d, 0x044e, 0x044f, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0x00, 0x00, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page04[256] = { + 0x00, 0xa8, 0x80, 0x81, 0xaa, 0xbd, 0xb2, 0xaf, /* 0x00-0x07 */ + 0xa3, 0x8a, 0x8c, 0x8e, 0x8d, 0x00, 0xa1, 0x8f, /* 0x08-0x0f */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x10-0x17 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x18-0x1f */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x20-0x27 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x28-0x2f */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x30-0x37 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x38-0x3f */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x40-0x47 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0x48-0x4f */ + 0x00, 0xb8, 0x90, 0x83, 0xba, 0xbe, 0xb3, 0xbf, /* 0x50-0x57 */ + 0xbc, 0x9a, 0x9c, 0x9e, 0x9d, 0x00, 0xa2, 0x9f, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0xa5, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +}; + +static unsigned char page20[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ + 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ +}; + +static unsigned char page21[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, page04, 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, + page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + 0x90, 0x83, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa2, 0xa2, 0xbc, 0xa4, 0xb4, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xb8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + 0x80, 0x81, 0x82, 0x81, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x80, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb2, 0xa5, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xa8, 0xb9, 0xaa, 0xbb, 0xa3, 0xbd, 0xbd, 0xaf, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "cp1251", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_cp1251(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_cp1251(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_cp1251) +module_exit(exit_nls_cp1251) + +/* + * 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: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_cp1255.c linux/fs/nls/nls_cp1255.c --- v2.4.3/linux/fs/nls/nls_cp1255.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nls/nls_cp1255.c Fri Apr 6 10:51:19 2001 @@ -0,0 +1,398 @@ +/* + * linux/fs/nls_cp1255.c + * + * Charset cp1255 translation tables. + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x20ac, 0x0000, 0x201a, 0x0192, + 0x201e, 0x2026, 0x2020, 0x2021, + 0x02c6, 0x2030, 0x0000, 0x2039, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x90*/ + 0x0000, 0x2018, 0x2019, 0x201c, + 0x201d, 0x2022, 0x2013, 0x2014, + 0x02dc, 0x2122, 0x0000, 0x203a, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xa0*/ + 0x00a0, 0x00a1, 0x00a2, 0x00a3, + 0x20aa, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00d7, 0x00ab, + 0x00ac, 0x00ad, 0x00ae, 0x203e, + /* 0xb0*/ + 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00f7, 0x00bb, + 0x00bc, 0x00bd, 0x00be, 0x00bf, + /* 0xc0*/ + 0x05b0, 0x05b1, 0x05b2, 0x05b3, + 0x05b4, 0x05b5, 0x05b6, 0x05b7, + 0x05b8, 0x05b9, 0x0000, 0x05bb, + 0x05bc, 0x05bd, 0x05be, 0x05bf, + /* 0xd0*/ + 0x05c0, 0x05c1, 0x05c2, 0x05c3, + 0x05f0, 0x05f1, 0x05f2, 0x05f3, + 0x05f4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2017, + /* 0xe0*/ + 0x05d0, 0x05d1, 0x05d2, 0x05d3, + 0x05d4, 0x05d5, 0x05d6, 0x05d7, + 0x05d8, 0x05d9, 0x05da, 0x05db, + 0x05dc, 0x05dd, 0x05de, 0x05df, + /* 0xf0*/ + 0x05e0, 0x05e1, 0x05e2, 0x05e3, + 0x05e4, 0x05e5, 0x05e6, 0x05e7, + 0x05e8, 0x05e9, 0x05ea, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */ +}; + +static unsigned char page01[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +}; + +static unsigned char page02[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ +}; + +static unsigned char page05[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xb0-0xb7 */ + 0xc8, 0xc9, 0x00, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xb8-0xbf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */ + 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ +}; + +static unsigned char page20[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfe, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ + 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0xa4, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ +}; + +static unsigned char page21[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, NULL, page05, 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, + page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "cp1255", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_cp1255(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_cp1255(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_cp1255) +module_exit(exit_nls_cp1255) + +/* + * 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: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_cp932.c linux/fs/nls/nls_cp932.c --- v2.4.3/linux/fs/nls/nls_cp932.c Fri Jul 21 15:19:51 2000 +++ linux/fs/nls/nls_cp932.c Fri Apr 6 10:51:19 2001 @@ -7819,73 +7819,68 @@ }; static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) + unsigned char *out, int boundlen) { unsigned char *uni2charset; unsigned char cl = uni&0xFF; unsigned char ch = (uni>>8)&0xFF; - int n; if (boundlen <= 0) return -ENAMETOOLONG; if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F) { out[0] = cl + 0x40; - n = 1; - return n; + return 1; } uni2charset = page_uni2charset[ch]; if (uni2charset) { - if (boundlen <= 1) + if (boundlen < 2) return -ENAMETOOLONG; + out[0] = uni2charset[cl*2]; out[1] = uni2charset[cl*2+1]; if (out[0] == 0x00 && out[1] == 0x00) return -EINVAL; - n = 2; - } else if (ch==0 && cl) { + return 2; + } else if ((ch == 0) && (cl <= 0x7F)) { out[0] = cl; - n = 1; + return 1; } else return -EINVAL; - - return n; } static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) + wchar_t *uni) { unsigned char ch, cl; wchar_t *charset2uni; - int n; if (boundlen <= 0) return -ENAMETOOLONG; - if (boundlen == 1) { + if (rawstring[0] <= 0x7F) { *uni = rawstring[0]; return 1; } + if (0xA1 <= rawstring[0] && rawstring[0] <= 0xDF) { + *uni = 0xFF00 | (rawstring[0] - 0x40); + return 1; + } + if (boundlen < 2) + return -ENAMETOOLONG; ch = rawstring[0]; cl = rawstring[1]; - if (0xA1 <= ch && ch <= 0xDF) { - *uni = 0xFF00 | (ch - 0x40); - n = 1; - return n; - } charset2uni = page_charset2uni[ch]; if (charset2uni && cl) { *uni = charset2uni[cl]; if (*uni == 0x0000) return -EINVAL; - n = 2; - } else{ - *uni = ch; - n = 1; + return 2; } - return n; + else + return -EINVAL; } static struct nls_table table = { diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_euc-jp.c linux/fs/nls/nls_euc-jp.c --- v2.4.3/linux/fs/nls/nls_euc-jp.c Mon Oct 16 12:58:51 2000 +++ linux/fs/nls/nls_euc-jp.c Fri Apr 6 10:51:19 2001 @@ -1,5 +1,9 @@ /* * linux/fs/nls_euc-jp.c + * + * Added `OSF/JVC Recommended Code Set Conversion Specification + * between Japanese EUC and Shift-JIS' support: <hirofumi@mail.parknet.co.jp> + * (http://www.opengroup.or.jp/jvc/cde/sjis-euc-e.html) */ #include <linux/module.h> @@ -10,49 +14,463 @@ static struct nls_table *p_nls; +#define IS_SJIS_LOW_BYTE(l) ((0x40 <= (l)) && ((l) <= 0xFC) && ((l) != 0x7F)) +/* JIS X 0208 (include NEC spesial characters) */ +#define IS_SJIS_JISX0208(h, l) ((((0x81 <= (h)) && ((h) <= 0x9F)) \ + || ((0xE0 <= (h)) && ((h) <= 0xEA))) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_JISX0201KANA(c) ((0xA1 <= (c)) && ((c) <= 0xDF)) +#define IS_SJIS_UDC_LOW(h, l) (((0xF0 <= (h)) && ((h) <= 0xF4)) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_UDC_HI(h, l) (((0xF5 <= (h)) && ((h) <= 0xF9)) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_IBM(h, l) (((0xFA <= (h)) && ((h) <= 0xFC)) \ + && IS_SJIS_LOW_BYTE(l)) +#define IS_SJIS_NECIBM(h, l) (((0xED <= (h)) && ((h) <= 0xEE)) \ + && IS_SJIS_LOW_BYTE(l)) +#define MAP_SJIS2EUC(sjis_hi, sjis_lo, sjis_p, euc_hi, euc_lo, euc_p) { \ + if ((sjis_lo) >= 0x9F) { \ + (euc_hi) = (sjis_hi) * 2 - (((sjis_p) * 2 - (euc_p)) - 1); \ + (euc_lo) = (sjis_lo) + 2; \ + } else { \ + (euc_hi) = (sjis_hi) * 2 - ((sjis_p) * 2 - (euc_p)); \ + (euc_lo) = (sjis_lo) + ((sjis_lo) >= 0x7F ? 0x60 : 0x61); \ + } \ +} while(0) #define SS2 (0x8E) /* Single Shift 2 */ #define SS3 (0x8F) /* Single Shift 3 */ +#define IS_EUC_BYTE(c) ((0xA1 <= (c)) && ((c) <= 0xFE)) +#define IS_EUC_JISX0208(h, l) (IS_EUC_BYTE(h) && IS_EUC_BYTE(l)) +#define IS_EUC_JISX0201KANA(h, l) (((h) == SS2) && (0xA1 <= (l) && (l) <= 0xDF)) +#define IS_EUC_UDC_LOW(h, l) (((0xF5 <= (h)) && ((h) <= 0xFE)) \ + && IS_EUC_BYTE(l)) +#define IS_EUC_UDC_HI(h, l) IS_EUC_UDC_LOW(h, l) /* G3 block */ +#define MAP_EUC2SJIS(euc_hi, euc_lo, euc_p, sjis_hi, sjis_lo, sjis_p) { \ + if ((euc_hi) & 1) { \ + (sjis_hi) = (euc_hi) / 2 + ((sjis_p) - (euc_p) / 2); \ + (sjis_lo) = (euc_lo) - ((euc_lo) >= 0xE0 ? 0x60 : 0x61); \ + } else { \ + (sjis_hi) = (euc_hi) / 2 + (((sjis_p) - (euc_p) / 2) - 1); \ + (sjis_lo) = (euc_lo) - 2; \ + } \ +} while(0) + +/* SJIS IBM extended characters to EUC map */ +static unsigned char sjisibm2euc_map[][2] = { + {0xF3, 0xF3}, {0xF3, 0xF4}, {0xF3, 0xF5}, {0xF3, 0xF6}, {0xF3, 0xF7}, + {0xF3, 0xF8}, {0xF3, 0xF9}, {0xF3, 0xFA}, {0xF3, 0xFB}, {0xF3, 0xFC}, + {0xF3, 0xFD}, {0xF3, 0xFE}, {0xF4, 0xA1}, {0xF4, 0xA2}, {0xF4, 0xA3}, + {0xF4, 0xA4}, {0xF4, 0xA5}, {0xF4, 0xA6}, {0xF4, 0xA7}, {0xF4, 0xA8}, + {0xA2, 0xCC}, {0xA2, 0xC3}, {0xF4, 0xA9}, {0xF4, 0xAA}, {0xF4, 0xAB}, + {0xF4, 0xAC}, {0xF4, 0xAD}, {0xA2, 0xE8}, {0xD4, 0xE3}, {0xDC, 0xDF}, + {0xE4, 0xE9}, {0xE3, 0xF8}, {0xD9, 0xA1}, {0xB1, 0xBB}, {0xF4, 0xAE}, + {0xC2, 0xAD}, {0xC3, 0xFC}, {0xE4, 0xD0}, {0xC2, 0xBF}, {0xBC, 0xF4}, + {0xB0, 0xA9}, {0xB0, 0xC8}, {0xF4, 0xAF}, {0xB0, 0xD2}, {0xB0, 0xD4}, + {0xB0, 0xE3}, {0xB0, 0xEE}, {0xB1, 0xA7}, {0xB1, 0xA3}, {0xB1, 0xAC}, + {0xB1, 0xA9}, {0xB1, 0xBE}, {0xB1, 0xDF}, {0xB1, 0xD8}, {0xB1, 0xC8}, + {0xB1, 0xD7}, {0xB1, 0xE3}, {0xB1, 0xF4}, {0xB1, 0xE1}, {0xB2, 0xA3}, + {0xF4, 0xB0}, {0xB2, 0xBB}, {0xB2, 0xE6}, {0x00, 0x00}, {0xB2, 0xED}, + {0xB2, 0xF5}, {0xB2, 0xFC}, {0xF4, 0xB1}, {0xB3, 0xB5}, {0xB3, 0xD8}, + {0xB3, 0xDB}, {0xB3, 0xE5}, {0xB3, 0xEE}, {0xB3, 0xFB}, {0xF4, 0xB2}, + {0xF4, 0xB3}, {0xB4, 0xC0}, {0xB4, 0xC7}, {0xB4, 0xD0}, {0xB4, 0xDE}, + {0xF4, 0xB4}, {0xB5, 0xAA}, {0xF4, 0xB5}, {0xB5, 0xAF}, {0xB5, 0xC4}, + {0xB5, 0xE8}, {0xF4, 0xB6}, {0xB7, 0xC2}, {0xB7, 0xE4}, {0xB7, 0xE8}, + {0xB7, 0xE7}, {0xF4, 0xB7}, {0xF4, 0xB8}, {0xF4, 0xB9}, {0xB8, 0xCE}, + {0xB8, 0xE1}, {0xB8, 0xF5}, {0xB8, 0xF7}, {0xB8, 0xF8}, {0xB8, 0xFC}, + {0xB9, 0xAF}, {0xB9, 0xB7}, {0xBA, 0xBE}, {0xBA, 0xDB}, {0xCD, 0xAA}, + {0xBA, 0xE1}, {0xF4, 0xBA}, {0xBA, 0xEB}, {0xBB, 0xB3}, {0xBB, 0xB8}, + {0xF4, 0xBB}, {0xBB, 0xCA}, {0xF4, 0xBC}, {0xF4, 0xBD}, {0xBB, 0xD0}, + {0xBB, 0xDE}, {0xBB, 0xF4}, {0xBB, 0xF5}, {0xBB, 0xF9}, {0xBC, 0xE4}, + {0xBC, 0xED}, {0xBC, 0xFE}, {0xF4, 0xBE}, {0xBD, 0xC2}, {0xBD, 0xE7}, + {0xF4, 0xBF}, {0xBD, 0xF0}, {0xBE, 0xB0}, {0xBE, 0xAC}, {0xF4, 0xC0}, + {0xBE, 0xB3}, {0xBE, 0xBD}, {0xBE, 0xCD}, {0xBE, 0xC9}, {0xBE, 0xE4}, + {0xBF, 0xA8}, {0xBF, 0xC9}, {0xC0, 0xC4}, {0xC0, 0xE4}, {0xC0, 0xF4}, + {0xC1, 0xA6}, {0xF4, 0xC1}, {0xC1, 0xF5}, {0xC1, 0xFC}, {0xF4, 0xC2}, + {0xC1, 0xF8}, {0xC2, 0xAB}, {0xC2, 0xA1}, {0xC2, 0xA5}, {0xF4, 0xC3}, + {0xC2, 0xB8}, {0xC2, 0xBA}, {0xF4, 0xC4}, {0xC2, 0xC4}, {0xC2, 0xD2}, + {0xC2, 0xD7}, {0xC2, 0xDB}, {0xC2, 0xDE}, {0xC2, 0xED}, {0xC2, 0xF0}, + {0xF4, 0xC5}, {0xC3, 0xA1}, {0xC3, 0xB5}, {0xC3, 0xC9}, {0xC3, 0xB9}, + {0xF4, 0xC6}, {0xC3, 0xD8}, {0xC3, 0xFE}, {0xF4, 0xC7}, {0xC4, 0xCC}, + {0xF4, 0xC8}, {0xC4, 0xD9}, {0xC4, 0xEA}, {0xC4, 0xFD}, {0xF4, 0xC9}, + {0xC5, 0xA7}, {0xC5, 0xB5}, {0xC5, 0xB6}, {0xF4, 0xCA}, {0xC5, 0xD5}, + {0xC6, 0xB8}, {0xC6, 0xD7}, {0xC6, 0xE0}, {0xC6, 0xEA}, {0xC6, 0xE3}, + {0xC7, 0xA1}, {0xC7, 0xAB}, {0xC7, 0xC7}, {0xC7, 0xC3}, {0xC7, 0xCB}, + {0xC7, 0xCF}, {0xC7, 0xD9}, {0xF4, 0xCB}, {0xF4, 0xCC}, {0xC7, 0xE6}, + {0xC7, 0xEE}, {0xC7, 0xFC}, {0xC7, 0xEB}, {0xC7, 0xF0}, {0xC8, 0xB1}, + {0xC8, 0xE5}, {0xC8, 0xF8}, {0xC9, 0xA6}, {0xC9, 0xAB}, {0xC9, 0xAD}, + {0xF4, 0xCD}, {0xC9, 0xCA}, {0xC9, 0xD3}, {0xC9, 0xE9}, {0xC9, 0xE3}, + {0xC9, 0xFC}, {0xC9, 0xF4}, {0xC9, 0xF5}, {0xF4, 0xCE}, {0xCA, 0xB3}, + {0xCA, 0xBD}, {0xCA, 0xEF}, {0xCA, 0xF1}, {0xCB, 0xAE}, {0xF4, 0xCF}, + {0xCB, 0xCA}, {0xCB, 0xE6}, {0xCB, 0xEA}, {0xCB, 0xF0}, {0xCB, 0xF4}, + {0xCB, 0xEE}, {0xCC, 0xA5}, {0xCB, 0xF9}, {0xCC, 0xAB}, {0xCC, 0xAE}, + {0xCC, 0xAD}, {0xCC, 0xB2}, {0xCC, 0xC2}, {0xCC, 0xD0}, {0xCC, 0xD9}, + {0xF4, 0xD0}, {0xCD, 0xBB}, {0xF4, 0xD1}, {0xCE, 0xBB}, {0xF4, 0xD2}, + {0xCE, 0xBA}, {0xCE, 0xC3}, {0xF4, 0xD3}, {0xCE, 0xF2}, {0xB3, 0xDD}, + {0xCF, 0xD5}, {0xCF, 0xE2}, {0xCF, 0xE9}, {0xCF, 0xED}, {0xF4, 0xD4}, + {0xF4, 0xD5}, {0xF4, 0xD6}, {0x00, 0x00}, {0xF4, 0xD7}, {0xD0, 0xE5}, + {0xF4, 0xD8}, {0xD0, 0xE9}, {0xD1, 0xE8}, {0xF4, 0xD9}, {0xF4, 0xDA}, + {0xD1, 0xEC}, {0xD2, 0xBB}, {0xF4, 0xDB}, {0xD3, 0xE1}, {0xD3, 0xE8}, + {0xD4, 0xA7}, {0xF4, 0xDC}, {0xF4, 0xDD}, {0xD4, 0xD4}, {0xD4, 0xF2}, + {0xD5, 0xAE}, {0xF4, 0xDE}, {0xD7, 0xDE}, {0xF4, 0xDF}, {0xD8, 0xA2}, + {0xD8, 0xB7}, {0xD8, 0xC1}, {0xD8, 0xD1}, {0xD8, 0xF4}, {0xD9, 0xC6}, + {0xD9, 0xC8}, {0xD9, 0xD1}, {0xF4, 0xE0}, {0xF4, 0xE1}, {0xF4, 0xE2}, + {0xF4, 0xE3}, {0xF4, 0xE4}, {0xDC, 0xD3}, {0xDD, 0xC8}, {0xDD, 0xD4}, + {0xDD, 0xEA}, {0xDD, 0xFA}, {0xDE, 0xA4}, {0xDE, 0xB0}, {0xF4, 0xE5}, + {0xDE, 0xB5}, {0xDE, 0xCB}, {0xF4, 0xE6}, {0xDF, 0xB9}, {0xF4, 0xE7}, + {0xDF, 0xC3}, {0xF4, 0xE8}, {0xF4, 0xE9}, {0xE0, 0xD9}, {0xF4, 0xEA}, + {0xF4, 0xEB}, {0xE1, 0xE2}, {0xF4, 0xEC}, {0xF4, 0xED}, {0xF4, 0xEE}, + {0xE2, 0xC7}, {0xE3, 0xA8}, {0xE3, 0xA6}, {0xE3, 0xA9}, {0xE3, 0xAF}, + {0xE3, 0xB0}, {0xE3, 0xAA}, {0xE3, 0xAB}, {0xE3, 0xBC}, {0xE3, 0xC1}, + {0xE3, 0xBF}, {0xE3, 0xD5}, {0xE3, 0xD8}, {0xE3, 0xD6}, {0xE3, 0xDF}, + {0xE3, 0xE3}, {0xE3, 0xE1}, {0xE3, 0xD4}, {0xE3, 0xE9}, {0xE4, 0xA6}, + {0xE3, 0xF1}, {0xE3, 0xF2}, {0xE4, 0xCB}, {0xE4, 0xC1}, {0xE4, 0xC3}, + {0xE4, 0xBE}, {0xF4, 0xEF}, {0xE4, 0xC0}, {0xE4, 0xC7}, {0xE4, 0xBF}, + {0xE4, 0xE0}, {0xE4, 0xDE}, {0xE4, 0xD1}, {0xF4, 0xF0}, {0xE4, 0xDC}, + {0xE4, 0xD2}, {0xE4, 0xDB}, {0xE4, 0xD4}, {0xE4, 0xFA}, {0xE4, 0xEF}, + {0xE5, 0xB3}, {0xE5, 0xBF}, {0xE5, 0xC9}, {0xE5, 0xD0}, {0xE5, 0xE2}, + {0xE5, 0xEA}, {0xE5, 0xEB}, {0xF4, 0xF1}, {0xF4, 0xF2}, {0xF4, 0xF3}, + {0xE6, 0xE8}, {0xE6, 0xEF}, {0xE7, 0xAC}, {0xF4, 0xF4}, {0xE7, 0xAE}, + {0xF4, 0xF5}, {0xE7, 0xB1}, {0xF4, 0xF6}, {0xE7, 0xB2}, {0xE8, 0xB1}, + {0xE8, 0xB6}, {0xF4, 0xF7}, {0xF4, 0xF8}, {0xE8, 0xDD}, {0xF4, 0xF9}, + {0xF4, 0xFA}, {0xE9, 0xD1}, {0xF4, 0xFB}, {0xE9, 0xED}, {0xEA, 0xCD}, + {0xF4, 0xFC}, {0xEA, 0xDB}, {0xEA, 0xE6}, {0xEA, 0xEA}, {0xEB, 0xA5}, + {0xEB, 0xFB}, {0xEB, 0xFA}, {0xF4, 0xFD}, {0xEC, 0xD6}, {0xF4, 0xFE}, +}; + +#define IS_EUC_IBM2JISX0208(h, l) \ + (((h) == 0xA2 && (l) == 0xCC) || ((h) == 0xA2 && (l) == 0xE8)) + +/* EUC to SJIS IBM extended characters map (G3 JIS X 0212 block) */ +static struct { + unsigned short euc; + unsigned char sjis[2]; +} euc2sjisibm_jisx0212_map[] = { + {0xA2C3, {0xFA, 0x55}}, {0xB0A9, {0xFA, 0x68}}, {0xB0C8, {0xFA, 0x69}}, + {0xB0D2, {0xFA, 0x6B}}, {0xB0D4, {0xFA, 0x6C}}, {0xB0E3, {0xFA, 0x6D}}, + {0xB0EE, {0xFA, 0x6E}}, {0xB1A3, {0xFA, 0x70}}, {0xB1A7, {0xFA, 0x6F}}, + {0xB1A9, {0xFA, 0x72}}, {0xB1AC, {0xFA, 0x71}}, {0xB1BB, {0xFA, 0x61}}, + {0xB1BE, {0xFA, 0x73}}, {0xB1C8, {0xFA, 0x76}}, {0xB1D7, {0xFA, 0x77}}, + {0xB1D8, {0xFA, 0x75}}, {0xB1DF, {0xFA, 0x74}}, {0xB1E1, {0xFA, 0x7A}}, + {0xB1E3, {0xFA, 0x78}}, {0xB1F4, {0xFA, 0x79}}, {0xB2A3, {0xFA, 0x7B}}, + {0xB2BB, {0xFA, 0x7D}}, {0xB2E6, {0xFA, 0x7E}}, {0xB2ED, {0xFA, 0x80}}, + {0xB2F5, {0xFA, 0x81}}, {0xB2FC, {0xFA, 0x82}}, {0xB3B5, {0xFA, 0x84}}, + {0xB3D8, {0xFA, 0x85}}, {0xB3DB, {0xFA, 0x86}}, {0xB3DD, {0xFB, 0x77}}, + {0xB3E5, {0xFA, 0x87}}, {0xB3EE, {0xFA, 0x88}}, {0xB3FB, {0xFA, 0x89}}, + {0xB4C0, {0xFA, 0x8C}}, {0xB4C7, {0xFA, 0x8D}}, {0xB4D0, {0xFA, 0x8E}}, + {0xB4DE, {0xFA, 0x8F}}, {0xB5AA, {0xFA, 0x91}}, {0xB5AF, {0xFA, 0x93}}, + {0xB5C4, {0xFA, 0x94}}, {0xB5E8, {0xFA, 0x95}}, {0xB7C2, {0xFA, 0x97}}, + {0xB7E4, {0xFA, 0x98}}, {0xB7E7, {0xFA, 0x9A}}, {0xB7E8, {0xFA, 0x99}}, + {0xB8CE, {0xFA, 0x9E}}, {0xB8E1, {0xFA, 0x9F}}, {0xB8F5, {0xFA, 0xA0}}, + {0xB8F7, {0xFA, 0xA1}}, {0xB8F8, {0xFA, 0xA2}}, {0xB8FC, {0xFA, 0xA3}}, + {0xB9AF, {0xFA, 0xA4}}, {0xB9B7, {0xFA, 0xA5}}, {0xBABE, {0xFA, 0xA6}}, + {0xBADB, {0xFA, 0xA7}}, {0xBAE1, {0xFA, 0xA9}}, {0xBAEB, {0xFA, 0xAB}}, + {0xBBB3, {0xFA, 0xAC}}, {0xBBB8, {0xFA, 0xAD}}, {0xBBCA, {0xFA, 0xAF}}, + {0xBBD0, {0xFA, 0xB2}}, {0xBBDE, {0xFA, 0xB3}}, {0xBBF4, {0xFA, 0xB4}}, + {0xBBF5, {0xFA, 0xB5}}, {0xBBF9, {0xFA, 0xB6}}, {0xBCE4, {0xFA, 0xB7}}, + {0xBCED, {0xFA, 0xB8}}, {0xBCF4, {0xFA, 0x67}}, {0xBCFE, {0xFA, 0xB9}}, + {0xBDC2, {0xFA, 0xBB}}, {0xBDE7, {0xFA, 0xBC}}, {0xBDF0, {0xFA, 0xBE}}, + {0xBEAC, {0xFA, 0xC0}}, {0xBEB0, {0xFA, 0xBF}}, {0xBEB3, {0xFA, 0xC2}}, + {0xBEBD, {0xFA, 0xC3}}, {0xBEC9, {0xFA, 0xC5}}, {0xBECD, {0xFA, 0xC4}}, + {0xBEE4, {0xFA, 0xC6}}, {0xBFA8, {0xFA, 0xC7}}, {0xBFC9, {0xFA, 0xC8}}, + {0xC0C4, {0xFA, 0xC9}}, {0xC0E4, {0xFA, 0xCA}}, {0xC0F4, {0xFA, 0xCB}}, + {0xC1A6, {0xFA, 0xCC}}, {0xC1F5, {0xFA, 0xCE}}, {0xC1F8, {0xFA, 0xD1}}, + {0xC1FC, {0xFA, 0xCF}}, {0xC2A1, {0xFA, 0xD3}}, {0xC2A5, {0xFA, 0xD4}}, + {0xC2AB, {0xFA, 0xD2}}, {0xC2AD, {0xFA, 0x63}}, {0xC2B8, {0xFA, 0xD6}}, + {0xC2BA, {0xFA, 0xD7}}, {0xC2BF, {0xFA, 0x66}}, {0xC2C4, {0xFA, 0xD9}}, + {0xC2D2, {0xFA, 0xDA}}, {0xC2D7, {0xFA, 0xDB}}, {0xC2DB, {0xFA, 0xDC}}, + {0xC2DE, {0xFA, 0xDD}}, {0xC2ED, {0xFA, 0xDE}}, {0xC2F0, {0xFA, 0xDF}}, + {0xC3A1, {0xFA, 0xE1}}, {0xC3B5, {0xFA, 0xE2}}, {0xC3B9, {0xFA, 0xE4}}, + {0xC3C9, {0xFA, 0xE3}}, {0xC3D8, {0xFA, 0xE6}}, {0xC3FC, {0xFA, 0x64}}, + {0xC3FE, {0xFA, 0xE7}}, {0xC4CC, {0xFA, 0xE9}}, {0xC4D9, {0xFA, 0xEB}}, + {0xC4EA, {0xFA, 0xEC}}, {0xC4FD, {0xFA, 0xED}}, {0xC5A7, {0xFA, 0xEF}}, + {0xC5B5, {0xFA, 0xF0}}, {0xC5B6, {0xFA, 0xF1}}, {0xC5D5, {0xFA, 0xF3}}, + {0xC6B8, {0xFA, 0xF4}}, {0xC6D7, {0xFA, 0xF5}}, {0xC6E0, {0xFA, 0xF6}}, + {0xC6E3, {0xFA, 0xF8}}, {0xC6EA, {0xFA, 0xF7}}, {0xC7A1, {0xFA, 0xF9}}, + {0xC7AB, {0xFA, 0xFA}}, {0xC7C3, {0xFA, 0xFC}}, {0xC7C7, {0xFA, 0xFB}}, + {0xC7CB, {0xFB, 0x40}}, {0xC7CF, {0xFB, 0x41}}, {0xC7D9, {0xFB, 0x42}}, + {0xC7E6, {0xFB, 0x45}}, {0xC7EB, {0xFB, 0x48}}, {0xC7EE, {0xFB, 0x46}}, + {0xC7F0, {0xFB, 0x49}}, {0xC7FC, {0xFB, 0x47}}, {0xC8B1, {0xFB, 0x4A}}, + {0xC8E5, {0xFB, 0x4B}}, {0xC8F8, {0xFB, 0x4C}}, {0xC9A6, {0xFB, 0x4D}}, + {0xC9AB, {0xFB, 0x4E}}, {0xC9AD, {0xFB, 0x4F}}, {0xC9CA, {0xFB, 0x51}}, + {0xC9D3, {0xFB, 0x52}}, {0xC9E3, {0xFB, 0x54}}, {0xC9E9, {0xFB, 0x53}}, + {0xC9F4, {0xFB, 0x56}}, {0xC9F5, {0xFB, 0x57}}, {0xC9FC, {0xFB, 0x55}}, + {0xCAB3, {0xFB, 0x59}}, {0xCABD, {0xFB, 0x5A}}, {0xCAEF, {0xFB, 0x5B}}, + {0xCAF1, {0xFB, 0x5C}}, {0xCBAE, {0xFB, 0x5D}}, {0xCBCA, {0xFB, 0x5F}}, + {0xCBE6, {0xFB, 0x60}}, {0xCBEA, {0xFB, 0x61}}, {0xCBEE, {0xFB, 0x64}}, + {0xCBF0, {0xFB, 0x62}}, {0xCBF4, {0xFB, 0x63}}, {0xCBF9, {0xFB, 0x66}}, + {0xCCA5, {0xFB, 0x65}}, {0xCCAB, {0xFB, 0x67}}, {0xCCAD, {0xFB, 0x69}}, + {0xCCAE, {0xFB, 0x68}}, {0xCCB2, {0xFB, 0x6A}}, {0xCCC2, {0xFB, 0x6B}}, + {0xCCD0, {0xFB, 0x6C}}, {0xCCD9, {0xFB, 0x6D}}, {0xCDAA, {0xFA, 0xA8}}, + {0xCDBB, {0xFB, 0x6F}}, {0xCEBA, {0xFB, 0x73}}, {0xCEBB, {0xFB, 0x71}}, + {0xCEC3, {0xFB, 0x74}}, {0xCEF2, {0xFB, 0x76}}, {0xCFD5, {0xFB, 0x78}}, + {0xCFE2, {0xFB, 0x79}}, {0xCFE9, {0xFB, 0x7A}}, {0xCFED, {0xFB, 0x7B}}, + {0xD0E5, {0xFB, 0x81}}, {0xD0E9, {0xFB, 0x83}}, {0xD1E8, {0xFB, 0x84}}, + {0xD1EC, {0xFB, 0x87}}, {0xD2BB, {0xFB, 0x88}}, {0xD3E1, {0xFB, 0x8A}}, + {0xD3E8, {0xFB, 0x8B}}, {0xD4A7, {0xFB, 0x8C}}, {0xD4D4, {0xFB, 0x8F}}, + {0xD4E3, {0xFA, 0x5C}}, {0xD4F2, {0xFB, 0x90}}, {0xD5AE, {0xFB, 0x91}}, + {0xD7DE, {0xFB, 0x93}}, {0xD8A2, {0xFB, 0x95}}, {0xD8B7, {0xFB, 0x96}}, + {0xD8C1, {0xFB, 0x97}}, {0xD8D1, {0xFB, 0x98}}, {0xD8F4, {0xFB, 0x99}}, + {0xD9A1, {0xFA, 0x60}}, {0xD9C6, {0xFB, 0x9A}}, {0xD9C8, {0xFB, 0x9B}}, + {0xD9D1, {0xFB, 0x9C}}, {0xDCD3, {0xFB, 0xA2}}, {0xDCDF, {0xFA, 0x5D}}, + {0xDDC8, {0xFB, 0xA3}}, {0xDDD4, {0xFB, 0xA4}}, {0xDDEA, {0xFB, 0xA5}}, + {0xDDFA, {0xFB, 0xA6}}, {0xDEA4, {0xFB, 0xA7}}, {0xDEB0, {0xFB, 0xA8}}, + {0xDEB5, {0xFB, 0xAA}}, {0xDECB, {0xFB, 0xAB}}, {0xDFB9, {0xFB, 0xAD}}, + {0xDFC3, {0xFB, 0xAF}}, {0xE0D9, {0xFB, 0xB2}}, {0xE1E2, {0xFB, 0xB5}}, + {0xE2C7, {0xFB, 0xB9}}, {0xE3A6, {0xFB, 0xBB}}, {0xE3A8, {0xFB, 0xBA}}, + {0xE3A9, {0xFB, 0xBC}}, {0xE3AA, {0xFB, 0xBF}}, {0xE3AB, {0xFB, 0xC0}}, + {0xE3AF, {0xFB, 0xBD}}, {0xE3B0, {0xFB, 0xBE}}, {0xE3BC, {0xFB, 0xC1}}, + {0xE3BF, {0xFB, 0xC3}}, {0xE3C1, {0xFB, 0xC2}}, {0xE3D4, {0xFB, 0xCA}}, + {0xE3D5, {0xFB, 0xC4}}, {0xE3D6, {0xFB, 0xC6}}, {0xE3D8, {0xFB, 0xC5}}, + {0xE3DF, {0xFB, 0xC7}}, {0xE3E1, {0xFB, 0xC9}}, {0xE3E3, {0xFB, 0xC8}}, + {0xE3E9, {0xFB, 0xCB}}, {0xE3F1, {0xFB, 0xCD}}, {0xE3F2, {0xFB, 0xCE}}, + {0xE3F8, {0xFA, 0x5F}}, {0xE4A6, {0xFB, 0xCC}}, {0xE4BE, {0xFB, 0xD2}}, + {0xE4BF, {0xFB, 0xD6}}, {0xE4C0, {0xFB, 0xD4}}, {0xE4C1, {0xFB, 0xD0}}, + {0xE4C3, {0xFB, 0xD1}}, {0xE4C7, {0xFB, 0xD5}}, {0xE4CB, {0xFB, 0xCF}}, + {0xE4D0, {0xFA, 0x65}}, {0xE4D1, {0xFB, 0xD9}}, {0xE4D2, {0xFB, 0xDC}}, + {0xE4D4, {0xFB, 0xDE}}, {0xE4DB, {0xFB, 0xDD}}, {0xE4DC, {0xFB, 0xDB}}, + {0xE4DE, {0xFB, 0xD8}}, {0xE4E0, {0xFB, 0xD7}}, {0xE4E9, {0xFA, 0x5E}}, + {0xE4EF, {0xFB, 0xE0}}, {0xE4FA, {0xFB, 0xDF}}, {0xE5B3, {0xFB, 0xE1}}, + {0xE5BF, {0xFB, 0xE2}}, {0xE5C9, {0xFB, 0xE3}}, {0xE5D0, {0xFB, 0xE4}}, + {0xE5E2, {0xFB, 0xE5}}, {0xE5EA, {0xFB, 0xE6}}, {0xE5EB, {0xFB, 0xE7}}, + {0xE6E8, {0xFB, 0xEB}}, {0xE6EF, {0xFB, 0xEC}}, {0xE7AC, {0xFB, 0xED}}, + {0xE7AE, {0xFB, 0xEF}}, {0xE7B1, {0xFB, 0xF1}}, {0xE7B2, {0xFB, 0xF3}}, + {0xE8B1, {0xFB, 0xF4}}, {0xE8B6, {0xFB, 0xF5}}, {0xE8DD, {0xFB, 0xF8}}, + {0xE9D1, {0xFB, 0xFB}}, {0xE9ED, {0xFC, 0x40}}, {0xEACD, {0xFC, 0x41}}, + {0xEADB, {0xFC, 0x43}}, {0xEAE6, {0xFC, 0x44}}, {0xEAEA, {0xFC, 0x45}}, + {0xEBA5, {0xFC, 0x46}}, {0xEBFA, {0xFC, 0x48}}, {0xEBFB, {0xFC, 0x47}}, + {0xECD6, {0xFC, 0x4A}}, +}; + +/* EUC to SJIS IBM extended characters map (G3 Upper block) */ +static unsigned char euc2sjisibm_g3upper_map[][2] = { + {0xFA, 0x40}, {0xFA, 0x41}, {0xFA, 0x42}, {0xFA, 0x43}, {0xFA, 0x44}, + {0xFA, 0x45}, {0xFA, 0x46}, {0xFA, 0x47}, {0xFA, 0x48}, {0xFA, 0x49}, + {0xFA, 0x4A}, {0xFA, 0x4B}, {0xFA, 0x4C}, {0xFA, 0x4D}, {0xFA, 0x4E}, + {0xFA, 0x4F}, {0xFA, 0x50}, {0xFA, 0x51}, {0xFA, 0x52}, {0xFA, 0x53}, + {0xFA, 0x56}, {0xFA, 0x57}, {0xFA, 0x58}, {0xFA, 0x59}, {0xFA, 0x5A}, + {0xFA, 0x62}, {0xFA, 0x6A}, {0xFA, 0x7C}, {0xFA, 0x83}, {0xFA, 0x8A}, + {0xFA, 0x8B}, {0xFA, 0x90}, {0xFA, 0x92}, {0xFA, 0x96}, {0xFA, 0x9B}, + {0xFA, 0x9C}, {0xFA, 0x9D}, {0xFA, 0xAA}, {0xFA, 0xAE}, {0xFA, 0xB0}, + {0xFA, 0xB1}, {0xFA, 0xBA}, {0xFA, 0xBD}, {0xFA, 0xC1}, {0xFA, 0xCD}, + {0xFA, 0xD0}, {0xFA, 0xD5}, {0xFA, 0xD8}, {0xFA, 0xE0}, {0xFA, 0xE5}, + {0xFA, 0xE8}, {0xFA, 0xEA}, {0xFA, 0xEE}, {0xFA, 0xF2}, {0xFB, 0x43}, + {0xFB, 0x44}, {0xFB, 0x50}, {0xFB, 0x58}, {0xFB, 0x5E}, {0xFB, 0x6E}, + {0xFB, 0x70}, {0xFB, 0x72}, {0xFB, 0x75}, {0xFB, 0x7C}, {0xFB, 0x7D}, + {0xFB, 0x7E}, {0xFB, 0x80}, {0xFB, 0x82}, {0xFB, 0x85}, {0xFB, 0x86}, + {0xFB, 0x89}, {0xFB, 0x8D}, {0xFB, 0x8E}, {0xFB, 0x92}, {0xFB, 0x94}, + {0xFB, 0x9D}, {0xFB, 0x9E}, {0xFB, 0x9F}, {0xFB, 0xA0}, {0xFB, 0xA1}, + {0xFB, 0xA9}, {0xFB, 0xAC}, {0xFB, 0xAE}, {0xFB, 0xB0}, {0xFB, 0xB1}, + {0xFB, 0xB3}, {0xFB, 0xB4}, {0xFB, 0xB6}, {0xFB, 0xB7}, {0xFB, 0xB8}, + {0xFB, 0xD3}, {0xFB, 0xDA}, {0xFB, 0xE8}, {0xFB, 0xE9}, {0xFB, 0xEA}, + {0xFB, 0xEE}, {0xFB, 0xF0}, {0xFB, 0xF2}, {0xFB, 0xF6}, {0xFB, 0xF7}, + {0xFB, 0xF9}, {0xFB, 0xFA}, {0xFB, 0xFC}, {0xFC, 0x42}, {0xFC, 0x49}, + {0xFC, 0x4B}, +}; + +#define MAP_ELEMENT_OF(map) (sizeof(map) / sizeof(map[0])) + +static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi, + const unsigned char sjis_lo); +static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo); +static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo); +static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo); +static inline int sjisnec2sjisibm(unsigned char *sjisibm, + const unsigned char sjisnec_hi, + const unsigned char sjisnec_lo); + +/* SJIS IBM extended characters to EUC */ +static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi, + const unsigned char sjis_lo) +{ + int index; + + index = ((sjis_hi - 0xFA) * (0xFD - 0x40)) + (sjis_lo - 0x40); + if (IS_EUC_IBM2JISX0208(sjisibm2euc_map[index][0], + sjisibm2euc_map[index][1])) { + euc[0] = sjisibm2euc_map[index][0]; + euc[1] = sjisibm2euc_map[index][1]; + return 2; + } else { + euc[0] = SS3; + euc[1] = sjisibm2euc_map[index][0]; + euc[2] = sjisibm2euc_map[index][1]; + return 3; + } +} + +/* EUC to SJIS IBM extended characters (G3 JIS X 0212 block) */ +static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo) +{ + int index, min_index, max_index; + unsigned short euc; + + min_index = 0; + max_index = MAP_ELEMENT_OF(euc2sjisibm_jisx0212_map) - 1; + euc = (euc_hi << 8) | euc_lo; + + while (min_index <= max_index) { + index = (min_index + max_index) / 2; + if (euc < euc2sjisibm_jisx0212_map[index].euc) + max_index = index - 1; + else + min_index = index + 1; + if (euc == euc2sjisibm_jisx0212_map[index].euc) { + sjis[0] = euc2sjisibm_jisx0212_map[index].sjis[0]; + sjis[1] = euc2sjisibm_jisx0212_map[index].sjis[1]; + return 3; + } + } + return 0; +} + +/* EUC to SJIS IBM extended characters (G3 Upper block) */ +static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo) +{ + int index; + + if (euc_hi == 0xF3) + index = ((euc_hi << 8) | euc_lo) - 0xF3F3; + else + index = ((euc_hi << 8) | euc_lo) - 0xF4A1 + 12; + + if ((index < 0) || (index >= MAP_ELEMENT_OF(euc2sjisibm_g3upper_map))) + return 0; + + sjis[0] = euc2sjisibm_g3upper_map[index][0]; + sjis[1] = euc2sjisibm_g3upper_map[index][1]; + + return 3; +} + +/* EUC to SJIS IBM extended characters (G3 block) */ +static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi, + const unsigned char euc_lo) +{ + int n; + +#if 0 + if ((euc_hi == 0xA2) && (euc_lo == 0xCC)) { + sjis[0] = 0xFA; + sjis[1] = 0x54; + return 2; + } else if ((euc_hi == 0xA2) && (euc_lo == 0xE8)) { + sjis[0] = 0xFA; + sjis[1] = 0x5B; + return 2; + } +#endif + if ((n = euc2sjisibm_g3upper(sjis, euc_hi, euc_lo))) { + return n; + } else if ((n = euc2sjisibm_jisx0212(sjis, euc_hi, euc_lo))) { + return n; + } + + return 0; +} + +/* NEC/IBM extended characters to IBM extended characters */ +static inline int sjisnec2sjisibm(unsigned char *sjisibm, + const unsigned char sjisnec_hi, + const unsigned char sjisnec_lo) +{ + int count; + + if (! IS_SJIS_NECIBM(sjisnec_hi, sjisnec_lo)) + return 0; + + if ((sjisnec_hi == 0xEE) && (sjisnec_lo == 0xF9)) { + sjisibm[0] = 0x81; + sjisibm[1] = 0xCA; + return 2; + } + + if ((sjisnec_hi == 0xEE) && (sjisnec_lo >= 0xEF)) { + count = (sjisnec_hi << 8 | sjisnec_lo) + - (sjisnec_lo <= 0xF9 ? 0xEEEF : (0xEEEF - 10)); + } else { + count = (sjisnec_hi - 0xED) * (0xFC - 0x40) + + (sjisnec_lo - 0x40) + (0x5C - 0x40); + if (sjisnec_lo >= 0x7F) + count--; + } + + sjisibm[0] = 0xFA + (count / (0xFC - 0x40)); + sjisibm[1] = 0x40 + (count % (0xFC - 0x40)); + if (sjisibm[1] >= 0x7F) + sjisibm[1]++; + + return 2; +} static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) + unsigned char *out, int boundlen) { int n; - if ( !p_nls ) - return -EINVAL; - if ( (n = p_nls->uni2char(uni, out, boundlen)) < 0) + if (!p_nls) + return -EINVAL; + if ((n = p_nls->uni2char(uni, out, boundlen)) < 0) return n; - + /* translate SJIS into EUC-JP */ if (n == 1) { - /* JIS X 201 KANA */ - if (0xA1 <= out[0] && out[0] <= 0xDF) { - if (boundlen <= 1) + if (IS_SJIS_JISX0201KANA(out[0])) { + /* JIS X 0201 KANA */ + if (boundlen < 2) return -ENAMETOOLONG; + out[1] = out[0]; out[0] = SS2; - n = 2; + return 2; } - } else if (n == 2) { - /* JIS X 208 */ + } else if (n == 2) { + /* NEC/IBM extended characters to IBM extended characters */ + sjisnec2sjisibm(out, out[0], out[1]); + + if (IS_SJIS_UDC_LOW(out[0], out[1])) { + /* User defined characters half low */ + MAP_SJIS2EUC(out[0], out[1], 0xF0, out[0], out[1], 0xF5); + } else if (IS_SJIS_UDC_HI(out[0], out[1])) { + /* User defined characters half high */ + unsigned char ch, cl; - /* SJIS codes 0xF0xx to 0xFFxx are machine-dependent codes and user-defining characters */ - if (out[0] >= 0xF0) { - out[0] = 0x81; /* 'GETA' with SJIS coding */ - out[1] = 0xAC; - } + if (boundlen < 3) + return -ENAMETOOLONG; - out[0] = (out[0]^0xA0)*2 + 0x5F; - if (out[1] > 0x9E) - out[0]++; - - if (out[1] < 0x7F) - out[1] = out[1] + 0x61; - else if (out[1] < 0x9F) - out[1] = out[1] + 0x60; - else - out[1] = out[1] + 0x02; + n = 3; ch = out[0]; cl = out[1]; + out[0] = SS3; + MAP_SJIS2EUC(ch, cl, 0xF5, out[1], out[2], 0xF5); + } else if (IS_SJIS_IBM(out[0], out[1])) { + /* IBM extended characters */ + unsigned char euc[3], i; + + n = sjisibm2euc(euc, out[0], out[1]); + if (boundlen < n) + return -ENAMETOOLONG; + for (i = 0; i < n; i++) + out[i] = euc[i]; + } else if (IS_SJIS_JISX0208(out[0], out[1])) { + /* JIS X 0208 (include NEC special characters) */ + out[0] = (out[0]^0xA0)*2 + 0x5F; + if (out[1] > 0x9E) + out[0]++; + + if (out[1] < 0x7F) + out[1] = out[1] + 0x61; + else if (out[1] < 0x9F) + out[1] = out[1] + 0x60; + else + out[1] = out[1] + 0x02; + } else { + /* Invalid characters */ + return -EINVAL; + } } else return -EINVAL; @@ -61,52 +479,73 @@ } static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) + wchar_t *uni) { unsigned char sjis_temp[2]; int euc_offset, n; - + if ( !p_nls ) return -EINVAL; if (boundlen <= 0) return -ENAMETOOLONG; - if (boundlen == 1) { - *uni = rawstring[0]; - return 1; - } - /* translate EUC-JP into SJIS */ if (rawstring[0] > 0x7F) { - if (rawstring[0] == SS2) { - /* JIS X 201 KANA */ - sjis_temp[0] = rawstring[1]; - sjis_temp[1] = 0x00; - euc_offset = 2; - } else if (rawstring[0] == SS3) { - /* JIS X 212 */ - sjis_temp[0] = 0x81; /* 'GETA' with SJIS coding */ - sjis_temp[1] = 0xAC; + if (rawstring[0] == SS3) { + if (boundlen < 3) + return -EINVAL; euc_offset = 3; - } else { - /* JIS X 208 */ - sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0; - if (!(rawstring[0]&1)) - sjis_temp[1] = rawstring[1] - 0x02; - else if (rawstring[1] < 0xE0) - sjis_temp[1] = rawstring[1] - 0x61; - else - sjis_temp[1] = rawstring[1] - 0x60; + + if (IS_EUC_UDC_HI(rawstring[1], rawstring[2])) { + /* User defined characters half high */ + MAP_EUC2SJIS(rawstring[1], rawstring[2], 0xF5, + sjis_temp[0], sjis_temp[1], 0xF5); + } else if (euc2sjisibm(sjis_temp,rawstring[1],rawstring[2])) { + /* IBM extended characters */ + } else { + /* JIS X 0212 and Invalid characters*/ + return -EINVAL; + + /* 'GETA' with SJIS coding */ + /* sjis_temp[0] = 0x81; */ + /* sjis_temp[1] = 0xAC; */ + } + } else { + if (boundlen < 2) + return -EINVAL; euc_offset = 2; + + if (IS_EUC_JISX0201KANA(rawstring[0], rawstring[1])) { + /* JIS X 0201 KANA */ + sjis_temp[0] = rawstring[1]; + sjis_temp[1] = 0x00; + } else if (IS_EUC_UDC_LOW(rawstring[0], rawstring[1])) { + /* User defined characters half low */ + MAP_EUC2SJIS(rawstring[0], rawstring[1], 0xF5, + sjis_temp[0], sjis_temp[1], 0xF0); + } else if (IS_EUC_JISX0208(rawstring[0], rawstring[1])) { + /* JIS X 0208 (include NEC spesial characters) */ + sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0; + if (!(rawstring[0] & 1)) + sjis_temp[1] = rawstring[1] - 0x02; + else if (rawstring[1] < 0xE0) + sjis_temp[1] = rawstring[1] - 0x61; + else + sjis_temp[1] = rawstring[1] - 0x60; + } else { + /* Invalid characters */ + return -EINVAL; + } } - } else { - /* JIS X 201 ROMAJI */ - sjis_temp[0] = rawstring[0]; - sjis_temp[1] = rawstring[1]; + } else { euc_offset = 1; + + /* JIS X 0201 ROMAJI */ + sjis_temp[0] = rawstring[0]; + sjis_temp[1] = 0x00; } - if ( (n = p_nls->char2uni(sjis_temp, boundlen, uni)) < 0) + if ( (n = p_nls->char2uni(sjis_temp, sizeof(sjis_temp), uni)) < 0) return n; return euc_offset; diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_iso8859-13.c linux/fs/nls/nls_iso8859-13.c --- v2.4.3/linux/fs/nls/nls_iso8859-13.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nls/nls_iso8859-13.c Fri Apr 6 10:51:19 2001 @@ -0,0 +1,330 @@ +/* + * linux/fs/nls_iso8859-13.c + * + * Charset iso8859-13 translation tables. + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x90*/ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xa0*/ + 0x00a0, 0x201d, 0x00a2, 0x00a3, + 0x00a4, 0x201e, 0x00a6, 0x00a7, + 0x00d8, 0x00a9, 0x0156, 0x00ab, + 0x00ac, 0x00ad, 0x00ae, 0x00c6, + /* 0xb0*/ + 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x201c, 0x00b5, 0x00b6, 0x00b7, + 0x00f8, 0x00b9, 0x0157, 0x00bb, + 0x00bc, 0x00bd, 0x00be, 0x00e6, + /* 0xc0*/ + 0x0104, 0x012e, 0x0100, 0x0106, + 0x00c4, 0x00c5, 0x0118, 0x0112, + 0x010c, 0x00c9, 0x0179, 0x0116, + 0x0122, 0x0136, 0x012a, 0x013b, + /* 0xd0*/ + 0x0160, 0x0143, 0x0145, 0x00d3, + 0x014c, 0x00d5, 0x00d6, 0x00d7, + 0x0172, 0x0141, 0x015a, 0x016a, + 0x00dc, 0x017b, 0x017d, 0x00df, + /* 0xe0*/ + 0x0105, 0x012f, 0x0101, 0x0107, + 0x00e4, 0x00e5, 0x0119, 0x0113, + 0x010d, 0x00e9, 0x017a, 0x0117, + 0x0123, 0x0137, 0x012b, 0x013c, + /* 0xf0*/ + 0x0161, 0x0144, 0x0146, 0x00f3, + 0x014d, 0x00f5, 0x00f6, 0x00f7, + 0x0173, 0x0142, 0x015b, 0x016b, + 0x00fc, 0x017c, 0x017e, 0x2019, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0x00, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0xaf, 0x00, /* 0xc0-0xc7 */ + 0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0xd3, 0x00, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xa8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe5, 0xbf, 0x00, /* 0xe0-0xe7 */ + 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0xf3, 0x00, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xb8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page01[256] = { + 0xc2, 0xe2, 0x00, 0x00, 0xc0, 0xe0, 0xc3, 0xe3, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0xc7, 0xe7, 0x00, 0x00, 0xcb, 0xeb, /* 0x10-0x17 */ + 0xc6, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0xce, 0xee, 0x00, 0x00, 0xc1, 0xe1, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xed, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0xcf, 0xef, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0xd9, 0xf9, 0xd1, 0xf1, 0xd2, 0xf2, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf4, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xba, /* 0x50-0x57 */ + 0x00, 0x00, 0xda, 0xfa, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0xd8, 0xf8, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0xca, 0xea, 0xdd, 0xfd, 0xde, 0xfe, 0x00, /* 0x78-0x7f */ +}; + +static unsigned char page02[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ +}; + +static unsigned char page20[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, page01, 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, + page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbf, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xbd, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "iso8859-13", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_iso8859_13(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_iso8859_13(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_iso8859_13) +module_exit(exit_nls_iso8859_13) + +/* + * 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: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_iso8859-8.c linux/fs/nls/nls_iso8859-8.c --- v2.4.3/linux/fs/nls/nls_iso8859-8.c Fri Jul 21 15:19:51 2000 +++ linux/fs/nls/nls_iso8859-8.c Fri Apr 6 10:51:19 2001 @@ -1,10 +1,5 @@ /* * linux/fs/nls_iso8859-8.c - * - * Charset iso8859-8 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. */ #include <linux/module.h> @@ -13,291 +8,36 @@ #include <linux/nls.h> #include <linux/errno.h> -static wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0x90*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xa0*/ - 0x00a0, 0x0000, 0x00a2, 0x00a3, - 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00d7, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x203e, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00f7, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x0000, - /* 0xc0*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xd0*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x2017, - /* 0xe0*/ - 0x05d0, 0x05d1, 0x05d2, 0x05d3, - 0x05d4, 0x05d5, 0x05d6, 0x05d7, - 0x05d8, 0x05d9, 0x05da, 0x05db, - 0x05dc, 0x05dd, 0x05de, 0x05df, - /* 0xf0*/ - 0x05e0, 0x05e1, 0x05e2, 0x05e3, - 0x05e4, 0x05e5, 0x05e6, 0x05e7, - 0x05e8, 0x05e9, 0x05ea, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, -}; - -static unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */ -}; - -static unsigned char page05[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ -}; - -static unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, /* 0x38-0x3f */ -}; - -static unsigned char *page_uni2charset[256] = { - page00, NULL, NULL, NULL, NULL, page05, 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, - page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} +static struct nls_table *p_nls; static struct nls_table table = { "iso8859-8", - uni2char, - char2uni, - charset2lower, - charset2upper, + NULL, + NULL, + NULL, + NULL, THIS_MODULE, }; static int __init init_nls_iso8859_8(void) { - return register_nls(&table); + p_nls = load_nls("cp1255"); + + if (p_nls) { + table.uni2char = p_nls->uni2char; + table.char2uni = p_nls->char2uni; + table.charset2upper = p_nls->charset2upper; + table.charset2lower = p_nls->charset2lower; + return register_nls(&table); + } + + return -EINVAL; } static void __exit exit_nls_iso8859_8(void) { unregister_nls(&table); + unload_nls(p_nls); } module_init(init_nls_iso8859_8) @@ -308,7 +48,8 @@ * 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: 8 * c-brace-imaginary-offset: 0 diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_koi8-u.c linux/fs/nls/nls_koi8-u.c --- v2.4.3/linux/fs/nls/nls_koi8-u.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nls/nls_koi8-u.c Fri Apr 6 10:51:19 2001 @@ -0,0 +1,345 @@ +/* + * linux/fs/nls_koi8-u.c + * + * Charset koi8-u translation tables. + * The Unicode to charset table has only exact mappings. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static wchar_t charset2uni[256] = { + /* 0x00*/ + 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, + /* 0x10*/ + 0x0010, 0x0011, 0x0012, 0x0013, + 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, + /* 0x20*/ + 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + /* 0x30*/ + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, + /* 0x40*/ + 0x0040, 0x0041, 0x0042, 0x0043, + 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, + /* 0x50*/ + 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, + 0x005c, 0x005d, 0x005e, 0x005f, + /* 0x60*/ + 0x0060, 0x0061, 0x0062, 0x0063, + 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, + /* 0x70*/ + 0x0070, 0x0071, 0x0072, 0x0073, + 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, + 0x007c, 0x007d, 0x007e, 0x007f, + /* 0x80*/ + 0x2500, 0x2502, 0x250c, 0x2510, + 0x2514, 0x2518, 0x251c, 0x2524, + 0x252c, 0x2534, 0x253c, 0x2580, + 0x2584, 0x2588, 0x258c, 0x2590, + /* 0x90*/ + 0x2591, 0x2592, 0x2593, 0x2320, + 0x25a0, 0x2219, 0x221a, 0x2248, + 0x2264, 0x2265, 0x00a0, 0x2321, + 0x00b0, 0x00b2, 0x00b7, 0x00f7, + /* 0xa0*/ + 0x2550, 0x2551, 0x2552, 0x0451, + 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255a, + 0x255b, 0x0491, 0x255d, 0x255e, + /* 0xb0*/ + 0x255f, 0x2560, 0x2561, 0x0401, + 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, + 0x256a, 0x0490, 0x256c, 0x00a9, + /* 0xc0*/ + 0x044e, 0x0430, 0x0431, 0x0446, + 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043a, + 0x043b, 0x043c, 0x043d, 0x043e, + /* 0xd0*/ + 0x043f, 0x044f, 0x0440, 0x0441, + 0x0442, 0x0443, 0x0436, 0x0432, + 0x044c, 0x044b, 0x0437, 0x0448, + 0x044d, 0x0449, 0x0447, 0x044a, + /* 0xe0*/ + 0x042e, 0x0410, 0x0411, 0x0426, + 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041a, + 0x041b, 0x041c, 0x041d, 0x041e, + /* 0xf0*/ + 0x041f, 0x042f, 0x0420, 0x0421, + 0x0422, 0x0423, 0x0416, 0x0412, + 0x042c, 0x042b, 0x0417, 0x0428, + 0x042d, 0x0429, 0x0427, 0x042a, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ +}; + +static unsigned char page04[256] = { + 0x00, 0xb3, 0x00, 0x00, 0xb4, 0x00, 0xb6, 0xb7, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ + 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */ + 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */ + 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */ + 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */ + 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */ + 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */ + 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */ + 0x00, 0xa3, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +}; + +static unsigned char page22[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ +}; + +static unsigned char page23[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ +}; + +static unsigned char page25[256] = { + 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0xa0, 0xa1, 0xa2, 0x00, 0xa5, 0x00, 0x00, 0xa8, /* 0x50-0x57 */ + 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */ + 0xb1, 0xb2, 0x00, 0xb5, 0x00, 0x00, 0xb8, 0xb9, /* 0x60-0x67 */ + 0xba, 0xbb, 0xbc, 0x00, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, page04, 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, page22, page23, NULL, page25, NULL, NULL, +}; + +static unsigned char charset2lower[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xa3, 0xa4, 0xb5, 0xa6, 0xa7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ +}; + +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0xb3, 0xb4, 0xa5, 0xb6, 0xb7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; + +static int uni2char(wchar_t uni, unsigned char *out, int boundlen) +{ + unsigned char *uni2charset; + unsigned char cl = uni & 0x00ff; + unsigned char ch = (uni & 0xff00) >> 8; + + if (boundlen <= 0) + return -ENAMETOOLONG; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + return -EINVAL; + return 1; +} + +static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) +{ + *uni = charset2uni[*rawstring]; + if (*uni == 0x0000) + return -EINVAL; + return 1; +} + +static struct nls_table table = { + "koi8-u", + uni2char, + char2uni, + charset2lower, + charset2upper, + THIS_MODULE, +}; + +static int __init init_nls_koi8_u(void) +{ + return register_nls(&table); +} + +static void __exit exit_nls_koi8_u(void) +{ + unregister_nls(&table); +} + +module_init(init_nls_koi8_u) +module_exit(exit_nls_koi8_u) + +/* + * 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: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v2.4.3/linux/fs/nls/nls_tis-620.c linux/fs/nls/nls_tis-620.c --- v2.4.3/linux/fs/nls/nls_tis-620.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nls/nls_tis-620.c Fri Apr 6 10:51:19 2001 @@ -0,0 +1,62 @@ +/* + * linux/fs/nls_tis-620.c + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/nls.h> +#include <linux/errno.h> + +static struct nls_table *p_nls; + +static struct nls_table table = { + "tis-620", + NULL, + NULL, + NULL, + NULL, + THIS_MODULE, +}; + +static int __init init_nls_tis_620(void) +{ + p_nls = load_nls("cp874"); + + if (p_nls) { + table.uni2char = p_nls->uni2char; + table.char2uni = p_nls->char2uni; + table.charset2upper = p_nls->charset2upper; + table.charset2lower = p_nls->charset2lower; + return register_nls(&table); + } + + return -EINVAL; +} + +static void __exit exit_nls_tis_620(void) +{ + unregister_nls(&table); + unload_nls(p_nls); +} + +module_init(init_nls_tis_620) +module_exit(exit_nls_tis_620) + +/* + * 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: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v2.4.3/linux/fs/partitions/Makefile linux/fs/partitions/Makefile --- v2.4.3/linux/fs/partitions/Makefile Fri Dec 29 14:07:23 2000 +++ linux/fs/partitions/Makefile Fri Apr 13 20:26:07 2001 @@ -9,7 +9,7 @@ O_TARGET := partitions.o -export-objs := check.o +export-objs := check.o ibm.o obj-y := check.o diff -u --recursive --new-file v2.4.3/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c --- v2.4.3/linux/fs/partitions/ibm.c Fri Feb 16 16:02:37 2001 +++ linux/fs/partitions/ibm.c Fri Apr 13 20:26:07 2001 @@ -1,14 +1,17 @@ /* * File...........: linux/fs/partitions/ibm.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Volker Sameske <sameske@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * History of changes (starts July 2000) - * 07/10/00 Fixed detection of CMS formatted disks - + * 07/10/00 Fixed detection of CMS formatted disks + * 02/13/00 VTOC partition support added */ +#include <linux/config.h> +#include <linux/module.h> #include <linux/fs.h> #include <linux/genhd.h> #include <linux/kernel.h> @@ -25,145 +28,177 @@ #include "ibm.h" #include "check.h" +#include <asm/vtoc.h> #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) /* We hook in when DASD is a module... */ int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL; +EXPORT_SYMBOL(genhd_dasd_fillgeo); +EXPORT_SYMBOL(genhd_dasd_name); #endif /* LINUX_IS_24 */ typedef enum { - ibm_partition_none = 0, - ibm_partition_lnx1 = 1, - ibm_partition_vol1 = 3, - ibm_partition_cms1 = 4 + ibm_partition_lnx1 = 0, + ibm_partition_vol1 = 1, + ibm_partition_cms1 = 2, + ibm_partition_none = 3 } ibm_partition_t; +static char* part_names[] = { [ibm_partition_lnx1] = "LNX1", + [ibm_partition_vol1] = "VOL1", + [ibm_partition_cms1] = "CMS1", + [ibm_partition_none] = "(nonl)" +}; + static ibm_partition_t get_partition_type ( char * type ) { - static char lnx[5]="LNX1"; - static char vol[5]="VOL1"; - static char cms[5]="CMS1"; - if ( ! strncmp ( lnx, "LNX1",4 ) ) { - ASCEBC(lnx,4); - ASCEBC(vol,4); - ASCEBC(cms,4); - } - if ( ! strncmp (type,lnx,4) || - ! strncmp (type,"LNX1",4) ) - return ibm_partition_lnx1; - if ( ! strncmp (type,vol,4) ) - return ibm_partition_vol1; - if ( ! strncmp (type,cms,4) ) - return ibm_partition_cms1; - return ibm_partition_none; + int i; + for ( i = 0; i < 3; i ++) { + if ( ! strncmp (type,part_names[i],4) ) + break; + } + return i; +} + +/* + * add the two default partitions + * - whole dasd + * - whole dasd without "offset" + */ +static inline void +two_partitions(struct gendisk *hd, + int minor, + int blocksize, + int offset, + int size) { + + add_gd_partition( hd, minor, 0,size); + add_gd_partition( hd, minor + 1, + offset * (blocksize >> 9), + size-offset*(blocksize>>9)); +} + + +/* + * compute the block number from a + * cyl-cyl-head-head structure + */ +static inline int +cchh2blk (cchh_t *ptr, struct hd_geometry *geo) { + return ptr->cc * geo->heads * geo->sectors + + ptr->hh * geo->sectors; +} + + +/* + * compute the block number from a + * cyl-cyl-head-head-block structure + */ +static inline int +cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) { + return ptr->cc * geo->heads * geo->sectors + + ptr->hh * geo->sectors + + ptr->b; } int ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor) { - struct buffer_head *bh; + struct buffer_head *bh, *buf; ibm_partition_t partition_type; char type[5] = {0,}; char name[7] = {0,}; struct hd_geometry geo; - mm_segment_t old_fs; int blocksize; - struct file *filp = NULL; - struct inode *inode = NULL; - int offset, size; + int offset=0, size=0, psize=0, counter=0; + unsigned int blk; + format1_label_t f1; + volume_label_t vlabel; + if ( first_sector != 0 ) { + BUG(); + } + if ( !genhd_dasd_fillgeo ) { + return 0; + } + genhd_dasd_fillgeo(dev,&geo); blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; if ( blocksize <= 0 ) { return 0; } - set_blocksize(dev, blocksize); /* OUCH !! */ - - /* find out offset of volume label (partn table) */ - inode = get_empty_inode(); - inode -> i_rdev = dev; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - inode -> i_bdev = bdget(kdev_t_to_nr(dev)); -#endif /* KERNEL_VERSION */ - filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL); - if (!filp) - return 0; - memset(filp,0,sizeof(struct file)); - filp ->f_mode = 1; /* read only */ - blkdev_open(inode,filp); - old_fs=get_fs(); - set_fs(KERNEL_DS); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo)); -#else - filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo)); -#endif /* KERNEL_VERSION */ - set_fs(old_fs); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) - blkdev_put(inode->i_bdev,BDEV_FILE); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - blkdev_close(inode,filp); -#else - blkdev_release(inode); -#endif /* LINUX_VERSION_CODE */ - size = hd -> sizes[MINOR(dev)]<<1; + set_blocksize(dev, blocksize); /* OUCH !! */ if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) { - strncpy ( type,bh -> b_data, 4); + strncpy ( type,bh -> b_data + 0, 4); strncpy ( name,bh -> b_data + 4, 6); + memcpy (&vlabel, bh->b_data, sizeof(volume_label_t)); } else { return 0; } - if ( (*(char *)bh -> b_data) & 0x80 ) { - EBCASC(name,6); - } - switch ( partition_type = get_partition_type(type) ) { - case ibm_partition_lnx1: - offset = (geo.start + 1); - printk ( "(LNX1)/%6s:",name); - break; - case ibm_partition_vol1: - offset = 0; - size = 0; - printk ( "(VOL1)/%6s:",name); - break; + EBCASC(type,4); + EBCASC(name,6); + + partition_type = get_partition_type(type); + printk ( "%6s/%6s:",part_names[partition_type],name); + switch ( partition_type ) { case ibm_partition_cms1: - printk ( "(CMS1)/%6s:",name); - if (* (((long *)bh->b_data) + 13) == 0) { - /* disk holds a CMS filesystem */ - offset = (geo.start + 1); - printk ("(CMS)"); - } else { + if (* (((long *)bh->b_data) + 13) != 0) { /* disk is reserved minidisk */ - // mdisk_setup_data.size[i] = - // (label[7] - 1 - label[13]) * - // (label[3] >> 9) >> 1; long *label=(long*)bh->b_data; blocksize = label[3]; offset = label[13]; size = (label[7]-1)*(blocksize>>9); printk ("(MDSK)"); + } else { + offset = (geo.start + 1); + size = hd -> sizes[MINOR(dev)]<<1; } + two_partitions( hd, MINOR(dev), blocksize, + offset, size); break; + case ibm_partition_lnx1: case ibm_partition_none: - printk ( "(nonl)/ :"); - offset = (geo.start+1); + offset = (geo.start + 1); + size = hd -> sizes[MINOR(dev)]<<1; + two_partitions( hd, MINOR(dev), blocksize, + offset, size); + break; + case ibm_partition_vol1: + add_gd_partition(hd, MINOR(dev), 0, size); + + /* get block number and read then first format1 label */ + blk = cchhb2blk(&vlabel.vtoc, &geo) + 1; + if ((buf = bread( dev, blk, blocksize)) != NULL) { + memcpy (&f1, buf->b_data, sizeof(format1_label_t)); + bforget(buf); + } + + while (f1.DS1FMTID == _ascebc['1']) { + offset = cchh2blk(&f1.DS1EXT1.llimit, &geo); + psize = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - + offset + 1; + + counter++; + add_gd_partition(hd, MINOR(dev) + counter, + offset * (blocksize >> 9), + psize * (blocksize >> 9)); + + blk++; + if ((buf = bread( dev, blk, blocksize)) != NULL) { + memcpy (&f1, buf->b_data, + sizeof(format1_label_t)); + bforget(buf); + } + } break; default: - offset = 0; - size = 0; - + add_gd_partition( hd, MINOR(dev), 0, 0); + add_gd_partition( hd, MINOR(dev) + 1, 0, 0); } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - add_gd_partition( hd, MINOR(dev), 0,size); - add_gd_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9), - size-offset*(blocksize>>9)); -#else - add_partition( hd, MINOR(dev), 0,size,0); - add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9), - size-offset*(blocksize>>9) ,0 ); -#endif /* LINUX_VERSION */ + printk ( "\n" ); bforget(bh); return 1; diff -u --recursive --new-file v2.4.3/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.4.3/linux/fs/proc/array.c Mon Mar 19 12:34:55 2001 +++ linux/fs/proc/array.c Fri Apr 6 10:51:19 2001 @@ -273,9 +273,6 @@ { char * orig = buffer; struct mm_struct *mm; -#if defined(CONFIG_ARCH_S390) - int line,len; -#endif buffer = task_name(task, buffer); buffer = task_state(task, buffer); @@ -291,8 +288,7 @@ buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); #if defined(CONFIG_ARCH_S390) - for(line=0;(len=sprintf_regs(line,buffer,task,NULL,NULL))!=0;line++) - buffer+=len; + buffer = task_show_regs(task, buffer); #endif return buffer - orig; } diff -u --recursive --new-file v2.4.3/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c --- v2.4.3/linux/fs/proc/proc_misc.c Fri Mar 23 11:45:28 2001 +++ linux/fs/proc/proc_misc.c Fri Apr 13 20:26:07 2001 @@ -274,8 +274,10 @@ user += kstat.per_cpu_user[cpu]; nice += kstat.per_cpu_nice[cpu]; system += kstat.per_cpu_system[cpu]; +#if !defined(CONFIG_ARCH_S390) for (j = 0 ; j < NR_IRQS ; j++) sum += kstat.irqs[cpu][j]; +#endif } len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system, @@ -299,8 +301,10 @@ kstat.pswpout, sum ); +#if !defined(CONFIG_ARCH_S390) for (i = 0 ; i < NR_IRQS ; i++) len += sprintf(page + len, " %u", kstat_irqs(i)); +#endif len += sprintf(page + len, "\ndisk_io: "); diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c --- v2.4.3/linux/fs/reiserfs/fix_node.c Fri Mar 2 18:38:39 2001 +++ linux/fs/reiserfs/fix_node.c Fri Apr 13 20:26:07 2001 @@ -479,7 +479,7 @@ // do not count last 'end_bytes' units of 'end_item'-th item end_bytes = (to_bytes != -1) ? to_bytes : 0; - /* go through all item begining from the start_item-th item and ending by + /* go through all item beginning from the start_item-th item and ending by the end_item-th item. Do not count first 'start_bytes' units of 'start_item'-th item and last 'end_bytes' of 'end_item'-th item */ diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/prints.c linux/fs/reiserfs/prints.c --- v2.4.3/linux/fs/reiserfs/prints.c Mon Jan 15 15:31:19 2001 +++ linux/fs/reiserfs/prints.c Fri Apr 13 20:26:07 2001 @@ -259,14 +259,14 @@ { do_reiserfs_warning; /* console_print (error_buf); */ - printk ("%s", error_buf); + printk (KERN_WARNING "%s", error_buf); } void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...) { #ifdef CONFIG_REISERFS_CHECK do_reiserfs_warning; - printk ("%s", error_buf); + printk (KERN_DEBUG "%s", error_buf); #else ; #endif diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c --- v2.4.3/linux/fs/reiserfs/stree.c Fri Mar 2 18:38:39 2001 +++ linux/fs/reiserfs/stree.c Fri Apr 13 20:26:07 2001 @@ -380,7 +380,7 @@ /* Parent at the path is not in the tree now. */ if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) ) return &MIN_KEY; - /* Check whether position in the parrent is correct. */ + /* Check whether position in the parent is correct. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) ) return &MIN_KEY; /* Check whether parent at the path really points to the child. */ diff -u --recursive --new-file v2.4.3/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c --- v2.4.3/linux/fs/reiserfs/super.c Fri Mar 2 11:12:12 2001 +++ linux/fs/reiserfs/super.c Fri Apr 13 20:26:07 2001 @@ -412,6 +412,7 @@ SB_BUFFER_WITH_SB (s) = bh; SB_DISK_SUPER_BLOCK (s) = rs; s->s_op = &reiserfs_sops; + s->s_maxbytes = MAX_NON_LFS; return 0; } #endif diff -u --recursive --new-file v2.4.3/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.4.3/linux/fs/romfs/inode.c Fri Mar 2 11:12:12 2001 +++ linux/fs/romfs/inode.c Fri Apr 13 20:26:07 2001 @@ -403,9 +403,11 @@ void *buf; int result = -EIO; + page_cache_get(page); lock_kernel(); - get_page(page); - buf = page_address(page); + buf = kmap(page); + if (!buf) + goto err_out; /* 32 bit warning -- but not for us :) */ offset = page->index << PAGE_CACHE_SHIFT; @@ -428,7 +430,9 @@ UnlockPage(page); - __free_page(page); + kunmap(page); +err_out: + page_cache_release(page); unlock_kernel(); return result; diff -u --recursive --new-file v2.4.3/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c --- v2.4.3/linux/fs/smbfs/ioctl.c Tue Jul 18 22:30:34 2000 +++ linux/fs/smbfs/ioctl.c Fri Apr 13 20:26:07 2001 @@ -45,7 +45,7 @@ if (!copy_from_user(&opt, (void *)arg, sizeof(opt))) result = smb_newconn(server, &opt); break; - default: + default:; } return result; diff -u --recursive --new-file v2.4.3/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.4.3/linux/fs/smbfs/proc.c Tue Mar 6 19:14:59 2001 +++ linux/fs/smbfs/proc.c Fri Apr 13 20:26:07 2001 @@ -697,7 +697,7 @@ #else /* * We don't want to be interrupted. For example, what if 'current' - * already has recieved a signal? sleep_on would terminate immediately + * already has received a signal? sleep_on would terminate immediately * and smbmount would not be able to re-establish connection. * * smbmount should be able to reconnect later, but it can't because @@ -712,7 +712,7 @@ if (server->state == CONN_VALID) { /* This should be changed to VERBOSE, except many smbfs problems is with the userspace daemon not reconnecting. */ - PARANOIA("sucessful, new pid=%d, generation=%d\n", + PARANOIA("successful, new pid=%d, generation=%d\n", server->conn_pid, server->generation); result = 1; } diff -u --recursive --new-file v2.4.3/linux/fs/stat.c linux/fs/stat.c --- v2.4.3/linux/fs/stat.c Tue Dec 5 12:29:39 2000 +++ linux/fs/stat.c Fri Apr 13 20:26:07 2001 @@ -25,7 +25,7 @@ } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) /* * For backward compatibility? Maybe this should be moved @@ -38,7 +38,7 @@ if (warncount > 0) { warncount--; - printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n", + printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", current->comm); } else if (warncount < 0) { /* it's laughable, but... */ @@ -53,7 +53,7 @@ SET_OLDSTAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); #if BITS_PER_LONG == 32 - if (inode->i_size > 0x7fffffff) + if (inode->i_size > MAX_NON_LFS) return -EOVERFLOW; #endif tmp.st_size = inode->i_size; @@ -79,7 +79,7 @@ SET_STAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); #if BITS_PER_LONG == 32 - if (inode->i_size > 0x7fffffff) + if (inode->i_size > MAX_NON_LFS) return -EOVERFLOW; #endif tmp.st_size = inode->i_size; diff -u --recursive --new-file v2.4.3/linux/fs/super.c linux/fs/super.c --- v2.4.3/linux/fs/super.c Sun Mar 25 18:17:00 2001 +++ linux/fs/super.c Tue Apr 17 14:39:50 2001 @@ -691,7 +691,7 @@ * the request. */ -struct super_block *get_empty_super(void) +static struct super_block *get_empty_super(void) { struct super_block *s; @@ -738,6 +738,7 @@ sema_init(&s->s_dquot.dqio_sem, 1); sema_init(&s->s_dquot.dqoff_sem, 1); s->s_dquot.flags = 0; + s->s_maxbytes = MAX_NON_LFS; lock_super(s); if (!type->read_super(s, data, silent)) goto out_fail; @@ -898,9 +899,9 @@ /* Need to clean after the sucker */ if (fs->fs_flags & FS_LITTER) d_genocide(root); - if (fs->fs_flags & (FS_SINGLE|FS_LITTER)) - shrink_dcache_parent(root); + shrink_dcache_parent(root); dput(root); + fsync_dev(sb->s_dev); lock_super(sb); if (sop) { if (sop->write_super && sb->s_dirt) @@ -1073,20 +1074,6 @@ if( (flags&MNT_FORCE) && sb->s_op->umount_begin) sb->s_op->umount_begin(sb); - - /* - * Shrink dcache, then fsync. This guarantees that if the - * filesystem is quiescent at this point, then (a) only the - * root entry should be in use and (b) that root entry is - * clean. - */ - shrink_dcache_sb(sb); - fsync_dev(sb->s_dev); - - if (sb->s_root->d_inode->i_state) { - mntput(mnt); - return -EBUSY; - } /* Something might grab it again - redo checks */ diff -u --recursive --new-file v2.4.3/linux/fs/udf/partition.c linux/fs/udf/partition.c --- v2.4.3/linux/fs/udf/partition.c Fri Feb 9 11:29:44 2001 +++ linux/fs/udf/partition.c Fri Apr 13 20:26:07 2001 @@ -162,6 +162,10 @@ mapsize = (rtl * sizeof(Uint32)) + ((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num); sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL); + if (!sdata->s_spar_map) { + printk("couldnt allocate UDF s_spar_map!\n"); + return; + } sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl]; memset(sdata->s_spar_map, 0xFF, mapsize); } diff -u --recursive --new-file v2.4.3/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.4.3/linux/fs/vfat/namei.c Fri Feb 9 11:29:44 2001 +++ linux/fs/vfat/namei.c Fri Apr 6 10:51:19 2001 @@ -10,6 +10,9 @@ * the problem, send a script that demonstrates it. * * Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de> + * + * Support Multibyte character and cleanup by + * OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> */ #define __NO_VERSION__ @@ -154,7 +157,7 @@ } return 1; } - +#if 0 /* not used functions */ static inline unsigned char vfat_getlower(struct nls_table *t, unsigned char c) { @@ -162,62 +165,185 @@ } static inline unsigned char -vfat_tolower(struct nls_table *t, unsigned char c) -{ - unsigned char nc = t->charset2lower[c]; - - return nc ? nc : c; -} - -static inline unsigned char vfat_getupper(struct nls_table *t, unsigned char c) { return t->charset2upper[c]; } -static inline unsigned char -vfat_toupper(struct nls_table *t, unsigned char c) +static inline int +vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound) { - unsigned char nc = t->charset2upper[c]; + int charlen; - return nc ? nc : c; + if ( (charlen = t->uni2char(uc, op, bound)) < 0) + charlen = 0; + + return charlen; } -static int -vfat_strnicmp(struct nls_table *t, const unsigned char *s1, - const unsigned char *s2, int len) +static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) { - while(len--) - if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++)) - return 1; + wchar_t *walk; + unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE]; + int chl, chi; + int space; + + if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) + return -EINVAL; + + if (IS_FREE(charbuf)) + return -EINVAL; + + chl = 0; + c = 0; + space = 1; /* disallow names starting with a dot */ + for (walk = name; len && walk-name < 8;) { + len--; + chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl < 0) + return -EINVAL; + + for (chi = 0; chi < chl; chi++) { + c = vfat_getupper(nls, charbuf[chi]); + if (!c) return -EINVAL; + if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; + if (strchr(replace_chars,c)) return -EINVAL; + if (c < ' '|| c==':') return -EINVAL; + if (c == '.') goto dot; + space = c == ' '; + } + } +dot:; + if (space) return -EINVAL; + if (len && c != '.') { + len--; + if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) { + if (charbuf[0] != '.') return -EINVAL; + } else + return -EINVAL; + c = '.'; + } + if (c == '.') { + if (len >= 4) return -EINVAL; + while (len > 0) { + len--; + chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl < 0) + return -EINVAL; + for (chi = 0; chi < chl; chi++) { + c = vfat_getupper(nls, charbuf[chi]); + if (!c) return -EINVAL; + if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; + if (strchr(replace_chars,c)) + return -EINVAL; + if (c < ' ' || c == '.'|| c==':') + return -EINVAL; + space = c == ' '; + } + } + if (space) return -EINVAL; + } return 0; } -static inline int -vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound) +static int vfat_format_name(struct nls_table *nls, wchar_t *name, + int len, char *res) { - int charlen; + char *walk; + unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; + int chi, chl; + int space; - if ( (charlen = t->uni2char(uc, op, bound)) < 0) - charlen = 0; + if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) + return -EINVAL; - return charlen; + if (IS_FREE(charbuf)) + return -EINVAL; + + space = 1; /* disallow names starting with a dot */ + for (walk = res; len--; ) { + chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl == 0) + return -EINVAL; + for (chi = 0; chi < chl; chi++){ + if (charbuf[chi] == '.') goto dot; + if (!charbuf[chi]) return -EINVAL; + if (walk-res == 8) return -EINVAL; + if (strchr(replace_chars,charbuf[chi])) return -EINVAL; + if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL; + space = charbuf[chi] == ' '; + *walk = charbuf[chi]; + walk++; + } + } +dot:; + if (space) return -EINVAL; + if (len >= 0) { + while (walk-res < 8) *walk++ = ' '; + while (len > 0 && walk-res < MSDOS_NAME) { + chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); + if (len < chl) + chl = len; + len -= chl; + for (chi = 0; chi < chl; chi++){ + if (!charbuf[chi]) return -EINVAL; + if (strchr(replace_chars,charbuf[chi])) + return -EINVAL; + if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':') + return -EINVAL; + space = charbuf[chi] == ' '; + *walk++ = charbuf[chi]; + } + } + if (space) return -EINVAL; + if (len) return -EINVAL; + } + while (walk-res < MSDOS_NAME) *walk++ = ' '; + + return 0; } static inline int vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound) { - int chi, chl; + int chl; if ( (chl = t->uni2char(uc, op, bound)) < 0) chl = 0; - for (chi = 0; chi < chl; chi++) - op[chi] = vfat_toupper(t, op[chi]); + if (chl == 1) + op[0] = vfat_toupper(t, op[0]); return chl; } +#endif +static inline unsigned char +vfat_tolower(struct nls_table *t, unsigned char c) +{ + unsigned char nc = t->charset2lower[c]; + + return nc ? nc : c; +} + +static inline unsigned char +vfat_toupper(struct nls_table *t, unsigned char c) +{ + unsigned char nc = t->charset2upper[c]; + + return nc ? nc : c; +} + +static int +vfat_strnicmp(struct nls_table *t, const unsigned char *s1, + const unsigned char *s2, int len) +{ + while(len--) + if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++)) + return 1; + + return 0; +} /* * Compute the hash for the vfat name corresponding to the dentry. @@ -383,8 +509,35 @@ /* Characters that are undesirable in an MS-DOS file name */ -static char bad_chars[] = "*?<>|\":/\\"; -static char replace_chars[] = "[];,+="; +static wchar_t bad_chars[] = { + /* `*' `?' `<' `>' `|' `"' `:' `/' `\' */ + 0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F, 0x005C, 0, +}; +#define IS_BADCHAR(uni) (vfat_unistrchr(bad_chars, (uni)) != NULL) + +static wchar_t replace_chars[] = { + /* `[' `]' `;' `,' `+' `=' */ + 0x005B, 0x005D, 0x003B, 0x002C, 0x002B, 0x003D, 0, +}; +#define IS_REPLACECHAR(uni) (vfat_unistrchr(replace_chars, (uni)) != NULL) + +static inline wchar_t *vfat_unistrchr(const wchar_t *s, const wchar_t c) +{ + for(; *s != c; ++s) + if (*s == 0) + return NULL; + return (wchar_t *) s; +} + +static inline int vfat_is_used_badchars(const wchar_t *s, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (s[i] < 0x0020 || IS_BADCHAR(s[i])) + return -EINVAL; + return 0; +} /* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal @@ -393,18 +546,10 @@ static int vfat_valid_longname(const char *name, int len, int xlate) { const char **reserved, *walk; - unsigned char c; - int i, baselen; + int baselen; if (len && name[len-1] == ' ') return -EINVAL; if (len >= 256) return -EINVAL; - for (i = 0; i < len; i++) { - c = name[i]; - if (xlate && c == ':') continue; - if (strchr(bad_chars,c)) { - return -EINVAL; - } - } if (len < 3) return 0; for (walk = name; *walk != 0 && *walk != '.'; walk++); @@ -424,72 +569,6 @@ return 0; } -static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) -{ - wchar_t *walk; - unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE]; - int chl, chi; - int space; - - if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) - return -EINVAL; - - if (IS_FREE(charbuf)) - return -EINVAL; - - chl = 0; - c = 0; - space = 1; /* disallow names starting with a dot */ - for (walk = name; len && walk-name < 8;) { - len--; - chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl < 0) - return -EINVAL; - - for (chi = 0; chi < chl; chi++) { - c = vfat_getupper(nls, charbuf[chi]); - if (!c) return -EINVAL; - if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; - if (strchr(replace_chars,c)) return -EINVAL; - if (c < ' '|| c==':') return -EINVAL; - if (c == '.') goto dot; - space = c == ' '; - } - } -dot:; - if (space) return -EINVAL; - if (len && c != '.') { - len--; - if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) { - if (charbuf[0] != '.') return -EINVAL; - } else - return -EINVAL; - c = '.'; - } - if (c == '.') { - if (len >= 4) return -EINVAL; - while (len > 0) { - len--; - chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl < 0) - return -EINVAL; - for (chi = 0; chi < chl; chi++) { - c = vfat_getupper(nls, charbuf[chi]); - if (!c) return -EINVAL; - if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; - if (strchr(replace_chars,c)) - return -EINVAL; - if (c < ' ' || c == '.'|| c==':') - return -EINVAL; - space = c == ' '; - } - } - if (space) return -EINVAL; - } - - return 0; -} - static int vfat_find_form(struct inode *dir,char *name) { struct msdos_dir_entry *de; @@ -503,127 +582,62 @@ return 0; } -static int vfat_format_name(struct nls_table *nls, wchar_t *name, - int len, char *res) -{ - char *walk; - unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; - int chi, chl; - int space; - - if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) - return -EINVAL; - - if (IS_FREE(charbuf)) - return -EINVAL; - - space = 1; /* disallow names starting with a dot */ - for (walk = res; len--; ) { - chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) - return -EINVAL; - for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == '.') goto dot; - if (!charbuf[chi]) return -EINVAL; - if (walk-res == 8) return -EINVAL; - if (strchr(replace_chars,charbuf[chi])) return -EINVAL; - if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL; - space = charbuf[chi] == ' '; - *walk = charbuf[chi]; - walk++; - } - } -dot:; - if (space) return -EINVAL; - if (len >= 0) { - while (walk-res < 8) *walk++ = ' '; - while (len > 0 && walk-res < MSDOS_NAME) { - chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); - if (len < chl) - chl = len; - len -= chl; - for (chi = 0; chi < chl; chi++){ - if (!charbuf[chi]) return -EINVAL; - if (strchr(replace_chars,charbuf[chi])) - return -EINVAL; - if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':') - return -EINVAL; - space = charbuf[chi] == ' '; - *walk++ = charbuf[chi]; - } - } - if (space) return -EINVAL; - if (len) return -EINVAL; - } - while (walk-res < MSDOS_NAME) *walk++ = ' '; - - return 0; -} - -static char skip_chars[] = ".:\"?<>| "; +static wchar_t skip_chars[] = { + /* `.' ` ' */ + 0x002E, 0x0020, 0, +}; +#define IS_SKIPCHAR(uni) \ + ((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1]) /* Given a valid longname, create a unique shortname. Make sure the * shortname does not exist + * Returns negative number on error, 0 for a normal + * return, and 1 for valid shortname */ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, - wchar_t *name, int len, - char *name_res) + wchar_t *uname, int ulen, + char *name_res) { - wchar_t *ip, *op, *ext_start, *end, *name_start; - wchar_t msdos_name[13]; - char base[9], ext[4], buf[8], *p; + wchar_t *ip, *ext_start, *end, *name_start; + unsigned char base[9], ext[4], buf[8], *p; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chl, chi; - int sz, extlen, baselen, i; - - PRINTK2(("Entering vfat_create_shortname\n")); - chl = 0; - sz = 0; /* Make compiler happy */ - if (len <= 12) { - /* Do a case insensitive search if the name would be a valid - * shortname if is were all capitalized. However, do not - * allow spaces in short names because Win95 scandisk does - * not like that */ - for (i = 0, op = &msdos_name[0], ip = name; ; i++, ip++, op++) { - if (i == len) { - if (vfat_format_name(nls, &msdos_name[0], len, - name_res) < 0) - break; - PRINTK3(("vfat_create_shortname 1\n")); - if (vfat_find_form(dir, name_res) < 0) - return 0; - return -EEXIST; - } - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == ' ') - break; - } - if (chi < chl) - break; + int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; + int is_uppercase, is_shortname; - *op = *ip; - } - } + /* + * 1) Valid characters for the 8.3 format alias are any + * combination of letters, uppercase alphabets, digits, any of + * the following special characters: + * $ % ' ` - @ { } ~ ! # ( ) & _ ^ + * In this case Longfilename is not stored in disk. + * + * 2) File name is 8.3 format, but it contain the lowercase + * alphabet etc. In this case numtail is not added, but + * Longfilename is stored. + * + * 3) When the one except for the above, or the following special + * character are contained: + * . [ ] ; , + = + * numtail is added, and Longfilename must be stored in disk . + */ + is_uppercase = 1; + is_shortname = 1; - PRINTK3(("vfat_create_shortname 3\n")); /* Now, we need to create a shortname from the long name */ - ext_start = end = &name[len]; - while (--ext_start >= name) { - chl = vfat_uni2upper_short(nls, *ext_start, charbuf, NLS_MAX_CHARSET_SIZE); - for (chi = 0; chi < chl; chi++) { - if (charbuf[chi] == '.') { - if (ext_start == end - 1) { - sz = len; - ext_start = NULL; - } - goto stop0; + ext_start = end = &uname[ulen]; + while (--ext_start >= uname) { + if (*ext_start == 0x002E) { /* is `.' */ + if (ext_start == end - 1) { + sz = ulen; + ext_start = NULL; } + break; } } -stop0:; - if (ext_start == name - 1) { - sz = len; + + if (ext_start == uname - 1) { + sz = ulen; ext_start = NULL; } else if (ext_start) { /* @@ -631,45 +645,63 @@ * an extension eg. "...test". In this case Win95 * uses the extension as the name and sets no extension. */ - name_start = &name[0]; - while (name_start < ext_start) - { - chl = vfat_uni2upper_short(nls, *name_start, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) + name_start = &uname[0]; + while (name_start < ext_start) { + if (!IS_SKIPCHAR(*name_start)) break; - for (chi = 0; chi < chl; chi++) - if (!strchr(skip_chars, charbuf[chi])) { - goto stop1; - } name_start++; } -stop1:; if (name_start != ext_start) { - sz = ext_start - name; + sz = ext_start - uname; ext_start++; } else { - sz = len; + sz = ulen; ext_start=NULL; } } - for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++, ip++) + numtail_baselen = 6; + numtail2_baselen = 2; + for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) { - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0){ - *p++ = '_'; - baselen++; + if (IS_SKIPCHAR(*ip)) { + is_shortname = 0; continue; } + if (IS_REPLACECHAR(*ip)) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else { + chl = nls->uni2char(*ip, charbuf, sizeof(charbuf)); + if (chl <= 0) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else if (chl == 1) { + unsigned char c = charbuf[0]; + charbuf[0] = vfat_toupper(nls, charbuf[0]); + if (c >= 0x7F || charbuf[0] != c) + is_uppercase = 0; + } else { + is_uppercase = 0; + } + } + if (baselen < 2 && (baselen + chl) > 2) + numtail2_baselen = baselen; + if (baselen < 6 && (baselen + chl) > 6) + numtail_baselen = baselen; for (chi = 0; chi < chl; chi++){ - if (!strchr(skip_chars, charbuf[chi])){ - if (strchr(replace_chars, charbuf[chi])) - *p = '_'; - else - *p = charbuf[chi]; - p++; baselen++; - } + *p++ = charbuf[chi]; + baselen++; + if (baselen >= 8) + break; + } + if (baselen >= 8) { + if ((chi < chl - 1) || (ip + 1) - uname < sz) + is_shortname = 0; + break; } } if (baselen == 0) { @@ -679,30 +711,51 @@ extlen = 0; if (ext_start) { for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) { - chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); - if (chl == 0) { - *p++ = '_'; - extlen++; + if (IS_SKIPCHAR(*ip)) { + is_shortname = 0; continue; } - - for (chi = 0; chi < chl; chi++) { - if (!strchr(skip_chars, charbuf[chi])) { - if (strchr(replace_chars, charbuf[chi])) - *p = '_'; - else - *p = charbuf[chi]; - p++; extlen++; + if (IS_REPLACECHAR(*ip)) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else { + chl = nls->uni2char(*ip, charbuf, sizeof(charbuf)); + if (chl <= 0) { + is_shortname = 0; + charbuf[0] = '_'; + chl = 1; + } else if (chl == 1) { + unsigned char c = charbuf[0]; + charbuf[0] = vfat_toupper(nls, charbuf[0]); + if (c >= 0x7F || charbuf[0] != c) + is_uppercase = 0; + } else { + is_uppercase = 0; } } + + if ((extlen + chl) > 3) { + is_shortname = 0; + break; + } + for (chi = 0; chi < chl; chi++) { + *p++ = charbuf[chi]; + extlen++; + } + if (extlen >= 3) { + if (ip + 1 != end) + is_shortname = 0; + break; + } } } ext[extlen] = '\0'; base[baselen] = '\0'; /* Yes, it can happen. ".\xe5" would do it. */ - if (IS_FREE(base)) - base[0]='_'; + if (base[0] == DELETED_FLAG) + base[0] = 0x05; /* OK, at this point we know that base is not longer than 8 symbols, * ext is not longer than 3, base is nonempty, both don't contain @@ -712,6 +765,14 @@ memset(name_res, ' ', MSDOS_NAME); memcpy(name_res,base,baselen); memcpy(name_res+8,ext,extlen); + + if (is_shortname) { + if (vfat_find_form(dir, name_res) < 0) + return is_uppercase; + else + return -EEXIST; + } + if (MSDOS_SB(dir->i_sb)->options.numtail == 0) if (vfat_find_form(dir, name_res) < 0) return 0; @@ -724,8 +785,10 @@ * values for part of the base. */ - if (baselen>6) - baselen = 6; + if (baselen>6) { + baselen = numtail_baselen; + name_res[7] = ' '; + } name_res[baselen] = '~'; for (i = 1; i < 10; i++) { name_res[baselen+1] = i + '0'; @@ -735,8 +798,10 @@ i = jiffies & 0xffff; sz = (jiffies >> 16) & 0x7; - if (baselen>2) - baselen = 2; + if (baselen>2) { + baselen = numtail2_baselen; + name_res[7] = ' '; + } name_res[baselen+4] = '~'; name_res[baselen+5] = '1' + sz; while (1) { @@ -868,15 +933,18 @@ goto out_free; uname = (wchar_t *) page; - if (vfat_valid_shortname(nls_disk, uname, ulen) >= 0) { - res = vfat_format_name(nls_disk, uname, ulen, de->name); - if (!res) - goto out_free; - } + res = vfat_is_used_badchars(uname, ulen); + if (res < 0) + goto out_free; res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name); - if (res) + if (res < 0) + goto out_free; + else if (res == 1) { + strncpy(de->name, msdos_name, MSDOS_NAME); + res = 0; goto out_free; + } *slots = unilen / 13; for (cksum = i = 0; i < 11; i++) { @@ -956,7 +1024,8 @@ goto cleanup; res = vfat_build_slots(dir, qname->name, len, ds, &slots); - if (res < 0) goto cleanup; + if (res < 0) + goto cleanup; offset = fat_add_entries(dir, slots, &bh1, &de1, &ino); if (offset < 0) { diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v2.4.3/linux/include/asm-alpha/io.h Fri Mar 2 11:12:07 2001 +++ linux/include/asm-alpha/io.h Fri Apr 13 20:26:07 2001 @@ -1,10 +1,6 @@ #ifndef __ALPHA_IO_H #define __ALPHA_IO_H -#include <linux/config.h> -#include <linux/kernel.h> -#include <asm/system.h> - /* We don't use IO slowdowns on the Alpha, but.. */ #define __SLOW_DOWN_IO do { } while (0) #define SLOW_DOWN_IO do { } while (0) @@ -19,6 +15,9 @@ #endif #ifdef __KERNEL__ +#include <linux/config.h> +#include <linux/kernel.h> +#include <asm/system.h> #include <asm/machvec.h> /* diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/ioctls.h linux/include/asm-alpha/ioctls.h --- v2.4.3/linux/include/asm-alpha/ioctls.h Thu Jan 27 16:40:09 2000 +++ linux/include/asm-alpha/ioctls.h Fri Apr 13 20:26:07 2001 @@ -106,5 +106,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #endif /* _ASM_ALPHA_IOCTLS_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h --- v2.4.3/linux/include/asm-alpha/pgalloc.h Fri Dec 29 14:07:23 2000 +++ linux/include/asm-alpha/pgalloc.h Fri Apr 13 20:26:07 2001 @@ -241,6 +241,9 @@ #define pte_quicklist (quicklists.pte_cache) #define pgtable_cache_size (quicklists.pgtable_cache_sz) +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) +#define pgd_populate(mm, pgd, pmd) pgd_set(pgd, pmd) + extern pgd_t *get_pgd_slow(void); static inline pgd_t *get_pgd_fast(void) @@ -268,9 +271,15 @@ free_page((unsigned long)pgd); } -extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked); +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL); + if (ret) + clear_page(ret); + return ret; +} -static inline pmd_t *get_pmd_fast(void) +static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -282,21 +291,27 @@ return (pmd_t *)ret; } -static inline void free_pmd_fast(pmd_t *pmd) +static inline void pmd_free_fast(pmd_t *pmd) { *(unsigned long *)pmd = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pmd; pgtable_cache_size++; } -static inline void free_pmd_slow(pmd_t *pmd) +static inline void pmd_free_slow(pmd_t *pmd) { free_page((unsigned long)pmd); } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} -static inline pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -308,66 +323,22 @@ return (pte_t *)ret; } -static inline void free_pte_fast(pte_t *pte) +static inline void pte_free_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -static inline void free_pte_slow(pte_t *pte) +static inline void pte_free_slow(pte_t *pte) { free_page((unsigned long)pte); } -extern void __bad_pte(pmd_t *pmd); -extern void __bad_pmd(pgd_t *pgd); - -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) -#define pmd_free(pmd) free_pmd_fast(pmd) +#define pte_free(pte) pte_free_fast(pte) +#define pmd_free(pmd) pmd_free_fast(pmd) #define pgd_free(pgd) free_pgd_fast(pgd) #define pgd_alloc() get_pgd_fast() - -static inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - pmd_set(pmd, page); - return page + address; - } - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -static inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *page = get_pmd_fast(); - - if (!page) - return get_pmd_slow(pgd, address); - pgd_set(pgd, page); - return page + address; - } - if (pgd_bad(*pgd)) { - __bad_pmd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + address; -} - -#define pte_alloc_kernel pte_alloc -#define pmd_alloc_kernel pmd_alloc extern int do_check_pgt_cache(int, int); diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h --- v2.4.3/linux/include/asm-alpha/pgtable.h Sun Dec 3 17:45:20 2000 +++ linux/include/asm-alpha/pgtable.h Fri Apr 13 20:26:07 2001 @@ -59,11 +59,6 @@ #define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */ #define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */ #define _PAGE_ASM 0x0010 -#if defined(CONFIG_ALPHA_EV6) && !defined(CONFIG_SMP) -#define _PAGE_MBE 0x0080 /* MB disable bit for EV6. */ -#else -#define _PAGE_MBE 0x0000 -#endif #define _PAGE_KRE 0x0100 /* xxx - see below on the "accessed" bit */ #define _PAGE_URE 0x0200 /* xxx */ #define _PAGE_KWE 0x1000 /* used to do the dirty bit in software */ @@ -90,20 +85,19 @@ #define _PFN_MASK 0xFFFFFFFF00000000 #define _PAGE_TABLE (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS) -#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_MBE) +#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS) /* - * All the normal masks have the "page accessed" bits on, as any time they - * are used, the page is accessed. They are cleared only by the page-out - * routines. + * All the normal masks have the "page accessed" bits on, as any time they are used, + * the page is accessed. They are cleared only by the page-out routines */ #define PAGE_NONE __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE) #define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS) #define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) #define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) -#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE | _PAGE_MBE) +#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE) -#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_MBE | (x)) +#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x)) #define _PAGE_P(x) _PAGE_NORMAL((x) | (((x) & _PAGE_FOW)?0:_PAGE_FOW)) #define _PAGE_S(x) _PAGE_NORMAL(x) @@ -195,7 +189,6 @@ * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ - #define mk_pte(page, pgprot) \ ({ \ pte_t pte; \ @@ -206,7 +199,7 @@ }) extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) -{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | (pgprot_val(pgprot) & ~_PAGE_MBE); return pte; } +{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; } extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } diff -u --recursive --new-file v2.4.3/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h --- v2.4.3/linux/include/asm-alpha/semaphore.h Fri Mar 2 11:12:07 2001 +++ linux/include/asm-alpha/semaphore.h Tue Apr 17 17:19:30 2001 @@ -13,6 +13,7 @@ #include <asm/atomic.h> #include <asm/compiler.h> /* __builtin_expect */ #include <linux/wait.h> +#include <linux/rwsem.h> #define DEBUG_SEMAPHORE 0 #define DEBUG_RW_SEMAPHORE 0 @@ -223,151 +224,6 @@ } #endif -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subtracting - * BIAS once per CPU will result in the int remaining - * negative. - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - * - * Once we start supporting machines with more than 128 CPUs, - * we should go for using a 64bit atomic type instead of 32bit - * as counter. We shall probably go for bias 0x80000000 then, - * so that single sethi can set it. - * - * -jj - */ - -#define RW_LOCK_BIAS 0x01000000 - -struct rw_semaphore { - atomic_t count; - /* bit 0 means read bias granted; - bit 1 means write bias granted. */ - unsigned granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ - { ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) \ - __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) \ - __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) \ - __DECLARE_RWSEM_GENERIC(name, 0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set (&sem->count, RW_LOCK_BIAS); - sem->granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -extern void down_read(struct rw_semaphore *); -extern void down_write(struct rw_semaphore *); -extern void up_read(struct rw_semaphore *); -extern void up_write(struct rw_semaphore *); -extern void __down_read_failed(struct rw_semaphore *, int); -extern void __down_write_failed(struct rw_semaphore *, int); -extern void __rwsem_wake(struct rw_semaphore *, int); - -static inline void __down_read(struct rw_semaphore *sem) -{ - long count = atomic_dec_return(&sem->count); - if (__builtin_expect(count < 0, 0)) - __down_read_failed(sem, count); -} - -static inline void __down_write(struct rw_semaphore *sem) -{ - long count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (__builtin_expect(count != 0, 0)) - __down_write_failed(sem, count); -} - -/* When a reader does a release, the only significant case is when there - was a writer waiting, and we've bumped the count to 0, then we must - wake the writer up. */ - -static inline void __up_read(struct rw_semaphore *sem) -{ - long count; - mb(); - count = atomic_inc_return(&sem->count); - if (__builtin_expect(count == 0, 0)) - __rwsem_wake(sem, 0); -} - -/* Releasing the writer is easy -- just release it and wake up - any sleepers. */ - -static inline void __up_write(struct rw_semaphore *sem) -{ - long count, wake; - mb(); - count = atomic_add_return(RW_LOCK_BIAS, &sem->count); - - /* Only do the wake if we were, but are no longer, negative. */ - wake = ((int)(count - RW_LOCK_BIAS) < 0) && count >= 0; - if (__builtin_expect(wake, 0)) - __rwsem_wake(sem, count); -} - -#if !WAITQUEUE_DEBUG && !DEBUG_RW_SEMAPHORE -extern inline void down_read(struct rw_semaphore *sem) -{ - __down_read(sem); -} -extern inline void down_write(struct rw_semaphore *sem) -{ - __down_write(sem); -} -extern inline void up_read(struct rw_semaphore *sem) -{ - __up_read(sem); -} -extern inline void up_write(struct rw_semaphore *sem) -{ - __up_write(sem); -} #endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h --- v2.4.3/linux/include/asm-arm/arch-arc/hardware.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-arc/hardware.h Thu Apr 12 12:20:31 2001 @@ -46,21 +46,28 @@ #define SCREEN_BASE 0x02000000 +#define EXPMASK_BASE 0x03360000 +#define IOEB_BASE 0x03350000 +#define VIDC_BASE 0x03400000 +#define LATCHA_BASE 0x03250040 +#define LATCHB_BASE 0x03250018 +#define IOC_BASE 0x03200000 +#define FLOPPYDMA_BASE 0x0302a000 +#define PCIO_BASE 0x03010000 + +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) + #ifndef __ASSEMBLY__ /* * for use with inb/outb */ -#define IO_VIDC_BASE 0x80100000 #ifdef CONFIG_ARCH_A5K -#define IOEB_VID_CTL 0x800d4012 -#define IOEB_PRESENT 0x800d4014 -#define IOEB_PSCLR 0x800d4016 -#define IOEB_MONTYPE 0x800d401c +#define IOEB_VID_CTL (IOEB_BASE + 0x48) +#define IOEB_PRESENT (IOEB_BASE + 0x50) +#define IOEB_PSCLR (IOEB_BASE + 0x58) +#define IOEB_MONTYPE (IOEB_BASE + 0x70) #endif -#define LATCHAADDR 0x80094010 -#define LATCHBADDR 0x80094006 -#define IOC_BASE 0x80080000 #define IO_EC_IOC4_BASE 0x8009c000 #define IO_EC_IOC_BASE 0x80090000 @@ -74,36 +81,9 @@ #define SCSI_BASE 0x03100000 #endif -/* - * IO definitions - */ -#define EXPMASK_BASE ((volatile unsigned char *)0x03360000) -#define IOEB_BASE ((volatile unsigned char *)0x03350050) -#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0x0302a000) -#define PCIO_BASE 0x03010000 - -/* - * RAM definitions - */ -#define GET_MEMORY_END(p) (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages)) -#define PARAMS_OFFSET 0x7c000 - -#else - -#define IOEB_BASE 0x03350050 -#define IOC_BASE 0x03200000 -#define PCIO_FLOPPYDMABASE 0x0302a000 -#define PCIO_BASE 0x03010000 - -#endif - -#ifndef __ASSEMBLY__ -#define __EXPMASK(offset) (((volatile unsigned char *)EXPMASK_BASE)[offset]) -#else -#define __EXPMASK(offset) offset #endif -#define EXPMASK_STATUS __EXPMASK(0x00) -#define EXPMASK_ENABLE __EXPMASK(0x04) +#define EXPMASK_STATUS (EXPMASK_BASE + 0x00) +#define EXPMASK_ENABLE (EXPMASK_BASE + 0x04) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h --- v2.4.3/linux/include/asm-arm/arch-arc/irq.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-arc/irq.h Thu Apr 12 12:20:31 2001 @@ -16,6 +16,7 @@ */ #include <linux/config.h> #include <asm/hardware/ioc.h> +#include <asm/io.h> #ifdef CONFIG_ARCH_ARC #define a_clf() clf() @@ -29,105 +30,81 @@ static void arc_mask_irq_ack_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; + mask = 1 << irq; a_clf(); - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]\n" -" strb %1, [%3]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)), - "r" (ioaddr(IOC_IRQCLRA))); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); + ioc_writeb(mask, IOC_IRQCLRA); a_stf(); } static void arc_mask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; + mask = 1 << irq; a_clf(); - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA))); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); a_stf(); } static void arc_unmask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; + mask = 1 << irq; a_clf(); - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA))); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val | mask, IOC_IRQMASKA); a_stf(); } static void arc_mask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_IRQMASKB); + ioc_writeb(val & ~mask, IOC_IRQMASKB); } static void arc_unmask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_IRQMASKB); + ioc_writeb(val | mask, IOC_IRQMASKB); } static void arc_mask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val & ~mask, IOC_FIQMASK); } static void arc_unmask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK))); + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val | mask, IOC_FIQMASK); } static __inline__ void irq_init_irq(void) { - extern void ecard_disableirq(unsigned int irq); - extern void ecard_enableirq(unsigned int irq); int irq; - outb(0, IOC_IRQMASKA); - outb(0, IOC_IRQMASKB); - outb(0, IOC_FIQMASK); + ioc_writeb(0, IOC_IRQMASKA); + ioc_writeb(0, IOC_IRQMASKB); + ioc_writeb(0, IOC_FIQMASK); for (irq = 0; irq < NR_IRQS; irq++) { switch (irq) { @@ -154,13 +131,6 @@ irq_desc[irq].mask_ack = arc_mask_irq_b; irq_desc[irq].mask = arc_mask_irq_b; irq_desc[irq].unmask = arc_unmask_irq_b; - break; - - case 32 ... 40: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = ecard_disableirq; - irq_desc[irq].mask = ecard_disableirq; - irq_desc[irq].unmask = ecard_enableirq; break; case 64 ... 72: diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h --- v2.4.3/linux/include/asm-arm/arch-arc/system.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-arc/system.h Thu Apr 12 12:20:31 2001 @@ -15,13 +15,6 @@ extern __inline__ void arch_reset(char mode) { - extern void ecard_reset(int card); - - /* - * Reset all expansion cards. - */ - ecard_reset(-1); - /* * copy branch instruction to reset location and call it */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/hardware.h linux/include/asm-arm/arch-cl7500/hardware.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/hardware.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-cl7500/hardware.h Thu Apr 12 12:20:31 2001 @@ -49,47 +49,18 @@ #define FLUSH_BASE 0xdf000000 - -#ifndef __ASSEMBLY__ - -/* - * for use with inb/outb - */ -#define IO_VIDC_AUDIO_BASE 0x80140000 -#define IO_VIDC_BASE 0x80100000 -#define IO_IOMD_BASE 0x80080000 -#define IOC_BASE 0x80080000 - -/* - * IO definitions - */ -#define EXPMASK_BASE ((volatile unsigned char *)0xe0360000) -#define IOEB_BASE ((volatile unsigned char *)0xe0350050) -#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000) +#define VIDC_BASE 0xe0400000 +#define IOMD_BASE 0xe0200000 +#define IOC_BASE 0xe0200000 +#define FLOPPYDMA_BASE 0xe002a000 #define PCIO_BASE 0xe0010000 -/* in/out bias for the ISA slot region */ -#define ISASLOT_IO 0x80400000 - -/* - * RAM definitions - */ -#define GET_MEMORY_END(p) (PAGE_OFFSET + p->u1.s.page_size * \ - (p->u1.s.pages_in_bank[0] + \ - p->u1.s.pages_in_bank[1] + \ - p->u1.s.pages_in_bank[2] + \ - p->u1.s.pages_in_bank[3])) #define FLUSH_BASE_PHYS 0x00000000 /* ROM */ -#else +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) -#define VIDC_SND_BASE 0xe0500000 -#define VIDC_BASE 0xe0400000 -#define IOMD_BASE 0xe0200000 -#define IOC_BASE 0xe0200000 -#define PCIO_FLOPPYDMABASE 0xe002a000 -#define PCIO_BASE 0xe0010000 +/* in/out bias for the ISA slot region */ +#define ISASLOT_IO 0x80400000 -#endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/irq.h linux/include/asm-arm/arch-cl7500/irq.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/irq.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-cl7500/irq.h Thu Apr 12 12:20:31 2001 @@ -2,14 +2,16 @@ * include/asm-arm/arch-cl7500/irq.h * * Copyright (C) 1996 Russell King - * Copyright (C) 1999 Nexus Electronics Ltd. + * Copyright (C) 1999, 2001 Nexus Electronics Ltd. * * Changelog: * 10-10-1996 RMK Brought up to date with arch-sa110eval * 22-08-1998 RMK Restructured IRQ routines * 11-08-1999 PJB Created ARM7500 version, derived from RiscPC code */ + #include <asm/hardware/iomd.h> +#include <asm/io.h> static inline int fixup_irq(unsigned int irq) { @@ -19,7 +21,7 @@ printk("Spurious ISA IRQ!\n"); return irq; } - irq = 40; + irq = IRQ_ISA_BASE; while (!(isabits & 1)) { irq++; isabits >>= 1; @@ -31,161 +33,121 @@ static void cl7500_mask_irq_ack_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]\n" -" strb %1, [%3]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)), - "r" (ioaddr(IOMD_IRQCLRA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); + iomd_writeb(mask, IOMD_IRQCLRA); } static void cl7500_mask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); } static void cl7500_unmask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val | mask, IOMD_IRQMASKA); } static void cl7500_mask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val & ~mask, IOMD_IRQMASKB); } static void cl7500_unmask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val | mask, IOMD_IRQMASKB); } static void cl7500_mask_irq_c(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKC))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKC); + iomd_writeb(val & ~mask, IOMD_IRQMASKC); } static void cl7500_unmask_irq_c(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKC))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKC); + iomd_writeb(val | mask, IOMD_IRQMASKC); } static void cl7500_mask_irq_d(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKD))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKD); + iomd_writeb(val & ~mask, IOMD_IRQMASKD); } static void cl7500_unmask_irq_d(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKD))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKD); + iomd_writeb(val | mask, IOMD_IRQMASKD); } static void cl7500_mask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val & ~mask, IOMD_DMAMASK); } static void cl7500_unmask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val | mask, IOMD_DMAMASK); } static void cl7500_mask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val & ~mask, IOMD_FIQMASK); } static void cl7500_unmask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val | mask, IOMD_FIQMASK); } static void no_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -196,14 +158,12 @@ static __inline__ void irq_init_irq(void) { - extern void ecard_disableirq(unsigned int irq); - extern void ecard_enableirq(unsigned int irq); int irq; - outb(0, IOMD_IRQMASKA); - outb(0, IOMD_IRQMASKB); - outb(0, IOMD_FIQMASK); - outb(0, IOMD_DMAMASK); + iomd_writeb(0, IOMD_IRQMASKA); + iomd_writeb(0, IOMD_IRQMASKB); + iomd_writeb(0, IOMD_FIQMASK); + iomd_writeb(0, IOMD_DMAMASK); for (irq = 0; irq < NR_IRQS; irq++) { switch (irq) { @@ -239,14 +199,14 @@ irq_desc[irq].unmask = cl7500_unmask_irq_c; break; - case 32 ... 39: + case 40 ... 47: irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = cl7500_mask_irq_d; irq_desc[irq].mask = cl7500_mask_irq_d; irq_desc[irq].unmask = cl7500_unmask_irq_d; break; - case 40 ... 47: + case 48 ... 55: irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 1; irq_desc[irq].mask_ack = no_action; diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/irqs.h linux/include/asm-arm/arch-cl7500/irqs.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/irqs.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-cl7500/irqs.h Thu Apr 12 12:20:31 2001 @@ -35,20 +35,22 @@ #define IRQ_IOP5 29 #define IRQ_IOP6 30 #define IRQ_IOP7 31 -#define IRQ_MOUSERX 32 -#define IRQ_MOUSETX 33 -#define IRQ_ADC 34 -#define IRQ_EVENT1 35 -#define IRQ_EVENT2 36 -#define IRQ_ISA_3 40 -#define IRQ_ISA_4 41 -#define IRQ_ISA_5 42 -#define IRQ_ISA_7 43 -#define IRQ_ISA_9 44 -#define IRQ_ISA_10 45 -#define IRQ_ISA_11 46 -#define IRQ_ISA_14 47 +#define IRQ_MOUSERX 40 +#define IRQ_MOUSETX 41 +#define IRQ_ADC 42 +#define IRQ_EVENT1 43 +#define IRQ_EVENT2 44 + +#define IRQ_ISA_BASE 48 +#define IRQ_ISA_3 48 +#define IRQ_ISA_4 49 +#define IRQ_ISA_5 50 +#define IRQ_ISA_7 51 +#define IRQ_ISA_9 52 +#define IRQ_ISA_10 53 +#define IRQ_ISA_11 54 +#define IRQ_ISA_14 55 #define FIQ_INT9 0 #define FIQ_INT5 1 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/shmparam.h linux/include/asm-arm/arch-cl7500/shmparam.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/shmparam.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/arch-cl7500/shmparam.h Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -/* - * linux/include/asm-arm/arch-cl7500/shmparam.h - * - * Copyright (c) 1999 Nexus Electronics Ltd - */ - -/* The processor-centric definitions are OK. */ - diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/system.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-cl7500/system.h Thu Apr 12 12:20:31 2001 @@ -11,12 +11,12 @@ static void arch_idle(void) { while (!current->need_resched && !hlt_counter) - outb(0, IOMD_SUSMODE); + iomd_writeb(0, IOMD_SUSMODE); } #define arch_reset(mode) \ do { \ - outb (0, IOMD_ROMCR0); \ + iomd_writeb(0, IOMD_ROMCR0); \ cpu_reset(0); \ } while (0); diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/time.h linux/include/asm-arm/arch-cl7500/time.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/time.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-cl7500/time.h Thu Apr 12 12:20:31 2001 @@ -13,18 +13,17 @@ { do_timer(regs); do_set_rtc(); + do_profile(regs); { /* Twinkle the lights. */ - static int count, state = 0xff; + static int count, state = 0xff00; if (count-- == 0) { - state ^= 1; + state ^= 0x100; count = 25; - *((volatile unsigned int *)(0xe002ba00)) = state; + *((volatile unsigned int *)LED_ADDRESS) = state; } } - - do_profile(regs); } /* @@ -32,6 +31,9 @@ */ extern __inline__ void setup_timer(void) { + extern void ioctime_init(void); + ioctime_init(); + timer_irq.handler = timer_interrupt; setup_arm_irq(IRQ_TIMER, &timer_irq); diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-cl7500/uncompress.h linux/include/asm-arm/arch-cl7500/uncompress.h --- v2.4.3/linux/include/asm-arm/arch-cl7500/uncompress.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-cl7500/uncompress.h Thu Apr 12 12:20:31 2001 @@ -1,11 +1,11 @@ /* * linux/include/asm-arm/arch-cl7500/uncompress.h * - * Copyright (C) 1999 Nexus Electronics Ltd. + * Copyright (C) 1999, 2000 Nexus Electronics Ltd. */ #define BASE 0x03010000 -#define SERBASE (BASE + (0x3f8 << 2)) +#define SERBASE (BASE + (0x2f8 << 2)) static __inline__ void putc(char c) { diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h --- v2.4.3/linux/include/asm-arm/arch-ebsa110/hardware.h Mon Sep 18 15:15:22 2000 +++ linux/include/asm-arm/arch-ebsa110/hardware.h Thu Apr 12 12:20:31 2001 @@ -12,41 +12,55 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#ifndef __ASSEMBLY__ - /* - * IO definitions + * The EBSA110 has a weird "ISA IO" region: + * + * Region 0 (addr = 0xf0000000 + io << 2) + * -------------------------------------------------------- + * Physical region IO region + * f0000fe0 - f0000ffc 3f8 - 3ff ttyS0 + * f0000e60 - f0000e64 398 - 399 + * f0000de0 - f0000dfc 378 - 37f lp0 + * f0000be0 - f0000bfc 2f8 - 2ff ttyS1 + * + * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1)) + * -------------------------------------------------------- + * Physical region IO region + * f00014f1 a79 pnp write data + * f00007c0 - f00007c1 3e0 - 3e1 pcmcia + * f00004f1 279 pnp address + * f0000440 - f000046c 220 - 236 eth0 + * f0000405 203 pnp read data */ -#define PIT_CTRL ((volatile unsigned char *)0xf200000d) -#define PIT_T2 ((volatile unsigned char *)0xf2000009) -#define PIT_T1 ((volatile unsigned char *)0xf2000005) -#define PIT_T0 ((volatile unsigned char *)0xf2000001) -/* - * Mapping areas - */ -#define IO_BASE 0xe0000000 +#define ISAMEM_PHYS 0xe0000000 +#define ISAMEM_SIZE 0x10000000 -/* - * RAM definitions - */ -#define FLUSH_BASE_PHYS 0x40000000 +#define ISAIO_PHYS 0xf0000000 +#define ISAIO_SIZE PGDIR_SIZE -#else /* __ASSEMBLY__ */ +#define TRICK0_PHYS 0xf2000000 +#define TRICK1_PHYS 0xf2400000 +#define TRICK2_PHYS 0xf2800000 +#define TRICK3_PHYS 0xf2c00000 +#define TRICK4_PHYS 0xf3000000 +#define TRICK5_PHYS 0xf3400000 +#define TRICK6_PHYS 0xf3800000 +#define TRICK7_PHYS 0xf3c00000 -#define IO_BASE 0 +#define ISAMEM_BASE 0xe0000000 +#define ISAIO_BASE 0xf0000000 -#endif /* __ASSEMBLY__ */ - -#define IO_SIZE 0x20000000 -#define IO_START 0xe0000000 +#define PIT_BASE 0xfc000000 +#define SOFT_BASE 0xfd000000 +/* + * RAM definitions + */ +#define FLUSH_BASE_PHYS 0x40000000 #define FLUSH_BASE 0xdf000000 -#define PCIO_BASE 0xf0000000 - -#define UNCACHEABLE_ADDR 0xf3000000 -#define PARAMS_OFFSET 0x400 +#define UNCACHEABLE_ADDR 0xff000000 /* IRQ_STAT */ #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/io.h linux/include/asm-arm/arch-ebsa110/io.h --- v2.4.3/linux/include/asm-arm/arch-ebsa110/io.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-ebsa110/io.h Thu Apr 12 12:20:31 2001 @@ -13,7 +13,7 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#define IO_SPACE_LIMIT 0xffffffff +#define IO_SPACE_LIMIT 0xffff /* * Generic virtual read/write @@ -21,6 +21,39 @@ #define __arch_getw(a) (*(volatile unsigned short *)(a)) #define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) -#define __io(p) (ISAIO_BASE + ((p) << 2)) +u8 __inb(int port); +u16 __inw(int port); +u32 __inl(int port); + +#define inb(p) __inb(p) +#define inw(p) __inw(p) +#define inl(p) __inl(p) + +void __outb(u8 val, int port); +void __outw(u16 val, int port); +void __outl(u32 val, int port); + +#define outb(v,p) __outb(v,p) +#define outw(v,p) __outw(v,p) +#define outl(v,p) __outl(v,p) + +u8 __readb(void *addr); +u16 __readw(void *addr); +u32 __readl(void *addr); + +#define readb(b) __readb(b) +#define readw(b) __readw(b) +#define readl(b) __readl(b) + +void __writeb(u8 val, void *addr); +void __writew(u16 val, void *addr); +void __writel(u32 val, void *addr); + +#define writeb(v,b) __writeb(v,b) +#define writew(v,b) __writew(v,b) +#define writel(v,b) __writel(v,b) + +#define __arch_ioremap(off,sz,c) ((void *)(off)) +#define __arch_iounmap(virt) do { } while (0) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/irq.h linux/include/asm-arm/arch-ebsa110/irq.h --- v2.4.3/linux/include/asm-arm/arch-ebsa110/irq.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-ebsa110/irq.h Thu Apr 12 12:20:31 2001 @@ -10,47 +10,4 @@ * Changelog: * 22-08-1998 RMK Restructured IRQ routines */ - -#define IRQ_MCLR ((volatile unsigned char *)0xf3000000) -#define IRQ_MSET ((volatile unsigned char *)0xf2c00000) -#define IRQ_MASK ((volatile unsigned char *)0xf2c00000) - -#define fixup_irq(x) (x) - -static void ebsa110_mask_and_ack_irq(unsigned int irq) -{ - *IRQ_MCLR = 1 << irq; -} - -static void ebsa110_mask_irq(unsigned int irq) -{ - *IRQ_MCLR = 1 << irq; -} - -static void ebsa110_unmask_irq(unsigned int irq) -{ - *IRQ_MSET = 1 << irq; -} - -static __inline__ void irq_init_irq(void) -{ - unsigned long flags; - int irq; - - save_flags_cli (flags); - *IRQ_MCLR = 0xff; - *IRQ_MSET = 0x55; - *IRQ_MSET = 0x00; - if (*IRQ_MASK != 0x55) - while (1); - *IRQ_MCLR = 0xff; /* 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_and_ack_irq; - irq_desc[irq].mask = ebsa110_mask_irq; - irq_desc[irq].unmask = ebsa110_unmask_irq; - } -} +#define fixup_irq(i) (i) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/memory.h linux/include/asm-arm/arch-ebsa110/memory.h --- v2.4.3/linux/include/asm-arm/arch-ebsa110/memory.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-ebsa110/memory.h Thu Apr 12 12:20:31 2001 @@ -35,13 +35,17 @@ #define PHYS_OFFSET (0x00000000UL) #define __virt_to_phys__is_a_macro -#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) #define __phys_to_virt__is_a_macro -#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) +/* + * We keep this 1:1 so that we don't interfere + * with the PCMCIA memory regions + */ #define __virt_to_bus__is_a_macro -#define __virt_to_bus(x) __virt_to_phys(x) +#define __virt_to_bus(x) (x) #define __bus_to_virt__is_a_macro -#define __bus_to_virt(x) __phys_to_virt(x) +#define __bus_to_virt(x) (x) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h --- v2.4.3/linux/include/asm-arm/arch-ebsa110/time.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-ebsa110/time.h Thu Apr 12 12:20:31 2001 @@ -18,39 +18,16 @@ #include <asm/leds.h> -#define MCLK_47_8 - -#if defined(MCLK_42_3) -#define PIT1_COUNT 0xecbe -#elif defined(MCLK_47_8) -/* - * This should be 0x10B43, but that doesn't exactly fit. - * We run the timer interrupt at 5ms, and then divide it by - * two in software... This is so that the user processes - * see exactly the same model whichever ARM processor they're - * running on. - */ -#define PIT1_COUNT 0x85A1 -#define DIVISOR 2 -#endif +extern int ebsa110_reset_timer(void); +extern void ebsa110_setup_timer(void); static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - *PIT_T1 = (PIT1_COUNT) & 0xff; - *PIT_T1 = (PIT1_COUNT) >> 8; - -#ifdef DIVISOR - { - static unsigned int divisor; - - if (divisor--) - return; - divisor = DIVISOR - 1; + if (ebsa110_reset_timer()) { + do_leds(); + do_timer(regs); + do_profile(regs); } -#endif - do_leds(); - do_timer(regs); - do_profile(regs); } /* @@ -58,17 +35,7 @@ */ extern __inline__ void setup_timer(void) { - /* - * Timer 1, mode 0, 16-bit, autoreload - */ - *PIT_CTRL = 0x70; - - /* - * Refresh counter clocked at 47.8MHz/7 = 146.4ns - * We want centi-second interrupts - */ - *PIT_T1 = (PIT1_COUNT) & 0xff; - *PIT_T1 = (PIT1_COUNT) >> 8; + ebsa110_setup_timer(); timer_irq.handler = timer_interrupt; diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa110/uncompress.h linux/include/asm-arm/arch-ebsa110/uncompress.h --- v2.4.3/linux/include/asm-arm/arch-ebsa110/uncompress.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-ebsa110/uncompress.h Thu Apr 12 12:20:31 2001 @@ -28,7 +28,11 @@ ldrb %0, [%2], #1 teq %0, #0 bne 1b -3: " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); +3: ldrb %1, [%3, #0x14] + and %1, %1, #0x60 + teq %1, #0x60 + bne 3b + " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); } /* diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h --- v2.4.3/linux/include/asm-arm/arch-ebsa285/irq.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-ebsa285/irq.h Thu Apr 12 12:20:31 2001 @@ -19,34 +19,7 @@ #include <asm/irq.h> #include <asm/mach-types.h> -/* - * Footbridge IRQ translation table - * Converts from our IRQ numbers into FootBridge masks - */ -static const int dc21285_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 int isa_irq = -1; +int isa_irq = -1; static inline int fixup_irq(unsigned int irq) { @@ -58,166 +31,3 @@ return irq; } -static void dc21285_mask_irq(unsigned int irq) -{ - *CSR_IRQ_DISABLE = dc21285_irq_mask[_DC21285_INR(irq)]; -} - -static void dc21285_unmask_irq(unsigned int irq) -{ - *CSR_IRQ_ENABLE = dc21285_irq_mask[_DC21285_INR(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 cpl, void *dev_id, struct pt_regs *regs) -{ -} - -static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; -static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; -static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; - -static __inline__ void irq_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 = dc21285_mask_irq; - irq_desc[irq].mask = dc21285_mask_irq; - irq_desc[irq].unmask = dc21285_unmask_irq; - } - - /* - * Determine the ISA settings for - * the machine we're running on. - */ - isa_irq = -1; - - if (footbridge_cfn_mode()) { - 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_irq = IRQ_PCI; - - if (machine_is_cats()) - isa_irq = IRQ_IN2; - - if (machine_is_netwinder()) - isa_irq = IRQ_IN3; - } - - if (isa_irq != -1) { - /* - * 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 */ - } 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; - } -} diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/aux_reg.h linux/include/asm-arm/arch-l7200/aux_reg.h --- v2.4.3/linux/include/asm-arm/arch-l7200/aux_reg.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/aux_reg.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-l7200/aux_reg.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 08-02-2000 SJH Created file + */ +#ifndef _ASM_ARCH_AUXREG_H +#define _ASM_ARCH_AUXREG_H + +#include <asm/arch/hardware.h> + +#define l7200aux_reg *((volatile unsigned int *) (AUX_BASE)) + +/* + * Auxillary register values + */ +#define AUX_CLEAR 0x00000000 +#define AUX_DIAG_LED_ON 0x00000002 +#define AUX_RTS_UART1 0x00000004 +#define AUX_DTR_UART1 0x00000008 +#define AUX_KBD_COLUMN_12_HIGH 0x00000010 +#define AUX_KBD_COLUMN_12_OFF 0x00000020 +#define AUX_KBD_COLUMN_13_HIGH 0x00000040 +#define AUX_KBD_COLUMN_13_OFF 0x00000080 + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/dma.h linux/include/asm-arm/arch-l7200/dma.h --- v2.4.3/linux/include/asm-arm/arch-l7200/dma.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-l7200/dma.h Thu Apr 12 12:20:31 2001 @@ -1,26 +1,24 @@ /* * linux/include/asm-arm/arch-l7200/dma.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 08-29-2000 SJH Created */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H +/* DMA is not yet implemented! It should be the same as acorn, copy over.. */ + /* * This is the maximum DMA address that can be DMAd to. * There should not be more than (0xd0000000 - 0xc0000000) * bytes of RAM. */ -#define MAX_DMA_ADDRESS 0xd0000000 -#define MAX_DMA_CHANNELS 8 - -#define DMA_0 0 -#define DMA_1 1 -#define DMA_2 2 -#define DMA_3 3 -#define DMA_S0 4 -#define DMA_S1 5 -#define DMA_VIRTUAL_FLOPPY 6 -#define DMA_VIRTUAL_SOUND 7 +#define MAX_DMA_ADDRESS 0xd0000000 +#define MAX_DMA_CHANNELS 0 -#define DMA_FLOPPY DMA_VIRTUAL_FLOPPY +#define DMA_S0 0 -#endif +#endif /* _ASM_ARCH_DMA_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/gp_timers.h linux/include/asm-arm/arch-l7200/gp_timers.h --- v2.4.3/linux/include/asm-arm/arch-l7200/gp_timers.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/gp_timers.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,42 @@ +/* + * linux/include/asm-arm/arch-l7200/gp_timers.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 07-28-2000 SJH Created file + * 08-02-2000 SJH Used structure for registers + */ +#ifndef _ASM_ARCH_GPTIMERS_H +#define _ASM_ARCH_GPTIMERS_H + +#include <asm/arch/hardware.h> + +/* + * Layout of L7200 general purpose timer registers + */ +struct GPT_Regs { + unsigned int TIMERLOAD; + unsigned int TIMERVALUE; + unsigned int TIMERCONTROL; + unsigned int TIMERCLEAR; +}; + +#define GPT_BASE (IO_BASE_2 + 0x3000) +#define l7200_timer1_regs ((volatile struct GPT_Regs *) (GPT_BASE)) +#define l7200_timer2_regs ((volatile struct GPT_Regs *) (GPT_BASE + 0x20)) + +/* + * General register values + */ +#define GPT_PRESCALE_1 0x00000000 +#define GPT_PRESCALE_16 0x00000004 +#define GPT_PRESCALE_256 0x00000008 +#define GPT_MODE_FREERUN 0x00000000 +#define GPT_MODE_PERIODIC 0x00000040 +#define GPT_ENABLE 0x00000080 +#define GPT_BZTOG 0x00000100 +#define GPT_BZMOD 0x00000200 +#define GPT_LOAD_MASK 0x0000ffff + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/gpio.h linux/include/asm-arm/arch-l7200/gpio.h --- v2.4.3/linux/include/asm-arm/arch-l7200/gpio.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/gpio.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,105 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/gpio.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * GPIO. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define GPIO_OFF 0x00005000 /* Offset from IO_START to the GPIO reg's. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */ +#define GPIO_BASE (IO_BASE_2 + GPIO_OFF) /* Virtual addr of the GPIO reg. */ + +/* Offsets from the start of the GPIO for all the registers. */ +#define PADR_OFF 0x000 +#define PADDR_OFF 0x004 +#define PASBSR_OFF 0x008 +#define PAEENR_OFF 0x00c +#define PAESNR_OFF 0x010 +#define PAESTR_OFF 0x014 +#define PAIMR_OFF 0x018 +#define PAINT_OFF 0x01c + +#define PBDR_OFF 0x020 +#define PBDDR_OFF 0x024 +#define PBSBSR_OFF 0x028 +#define PBIMR_OFF 0x038 +#define PBINT_OFF 0x03c + +#define PCDR_OFF 0x040 +#define PCDDR_OFF 0x044 +#define PCSBSR_OFF 0x048 +#define PCIMR_OFF 0x058 +#define PCINT_OFF 0x05c + +#define PDDR_OFF 0x060 +#define PDDDR_OFF 0x064 +#define PDSBSR_OFF 0x068 +#define PDEENR_OFF 0x06c +#define PDESNR_OFF 0x070 +#define PDESTR_OFF 0x074 +#define PDIMR_OFF 0x078 +#define PDINT_OFF 0x07c + +#define PEDR_OFF 0x080 +#define PEDDR_OFF 0x084 +#define PESBSR_OFF 0x088 +#define PEEENR_OFF 0x08c +#define PEESNR_OFF 0x090 +#define PEESTR_OFF 0x094 +#define PEIMR_OFF 0x098 +#define PEINT_OFF 0x09c + +/* Define the GPIO registers for use by device drivers and the kernel. */ +#define PADR (*(volatile unsigned long *)(GPIO_BASE+PADR_OFF)) +#define PADDR (*(volatile unsigned long *)(GPIO_BASE+PADDR_OFF)) +#define PASBSR (*(volatile unsigned long *)(GPIO_BASE+PASBSR_OFF)) +#define PAEENR (*(volatile unsigned long *)(GPIO_BASE+PAEENR_OFF)) +#define PAESNR (*(volatile unsigned long *)(GPIO_BASE+PAESNR_OFF)) +#define PAESTR (*(volatile unsigned long *)(GPIO_BASE+PAESTR_OFF)) +#define PAIMR (*(volatile unsigned long *)(GPIO_BASE+PAIMR_OFF)) +#define PAINT (*(volatile unsigned long *)(GPIO_BASE+PAINT_OFF)) + +#define PBDR (*(volatile unsigned long *)(GPIO_BASE+PBDR_OFF)) +#define PBDDR (*(volatile unsigned long *)(GPIO_BASE+PBDDR_OFF)) +#define PBSBSR (*(volatile unsigned long *)(GPIO_BASE+PBSBSR_OFF)) +#define PBIMR (*(volatile unsigned long *)(GPIO_BASE+PBIMR_OFF)) +#define PBINT (*(volatile unsigned long *)(GPIO_BASE+PBINT_OFF)) + +#define PCDR (*(volatile unsigned long *)(GPIO_BASE+PCDR_OFF)) +#define PCDDR (*(volatile unsigned long *)(GPIO_BASE+PCDDR_OFF)) +#define PCSBSR (*(volatile unsigned long *)(GPIO_BASE+PCSBSR_OFF)) +#define PCIMR (*(volatile unsigned long *)(GPIO_BASE+PCIMR_OFF)) +#define PCINT (*(volatile unsigned long *)(GPIO_BASE+PCINT_OFF)) + +#define PDDR (*(volatile unsigned long *)(GPIO_BASE+PDDR_OFF)) +#define PDDDR (*(volatile unsigned long *)(GPIO_BASE+PDDDR_OFF)) +#define PDSBSR (*(volatile unsigned long *)(GPIO_BASE+PDSBSR_OFF)) +#define PDEENR (*(volatile unsigned long *)(GPIO_BASE+PDEENR_OFF)) +#define PDESNR (*(volatile unsigned long *)(GPIO_BASE+PDESNR_OFF)) +#define PDESTR (*(volatile unsigned long *)(GPIO_BASE+PDESTR_OFF)) +#define PDIMR (*(volatile unsigned long *)(GPIO_BASE+PDIMR_OFF)) +#define PDINT (*(volatile unsigned long *)(GPIO_BASE+PDINT_OFF)) + +#define PEDR (*(volatile unsigned long *)(GPIO_BASE+PEDR_OFF)) +#define PEDDR (*(volatile unsigned long *)(GPIO_BASE+PEDDR_OFF)) +#define PESBSR (*(volatile unsigned long *)(GPIO_BASE+PESBSR_OFF)) +#define PEEENR (*(volatile unsigned long *)(GPIO_BASE+PEEENR_OFF)) +#define PEESNR (*(volatile unsigned long *)(GPIO_BASE+PEESNR_OFF)) +#define PEESTR (*(volatile unsigned long *)(GPIO_BASE+PEESTR_OFF)) +#define PEIMR (*(volatile unsigned long *)(GPIO_BASE+PEIMR_OFF)) +#define PEINT (*(volatile unsigned long *)(GPIO_BASE+PEINT_OFF)) + +#define VEE_EN 0x02 +#define BACKLIGHT_EN 0x04 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/hardware.h linux/include/asm-arm/arch-l7200/hardware.h --- v2.4.3/linux/include/asm-arm/arch-l7200/hardware.h Mon Nov 27 17:07:59 2000 +++ linux/include/asm-arm/arch-l7200/hardware.h Thu Apr 12 12:20:31 2001 @@ -13,6 +13,8 @@ * 04-21-2000 RS Changed mapping of I/O in virtual space * 04-25-2000 SJH Removed unused symbols and such * 05-05-2000 SJH Complete rewrite + * 07-31-2000 SJH Added undocumented debug auxillary port to + * get at last two columns for keyboard driver */ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H @@ -33,6 +35,18 @@ #define IO_START_2 0x90000000 /* I/O */ #define IO_SIZE_2 0x01000000 #define IO_BASE_2 0xd1000000 + +#define AUX_START 0x1a000000 /* AUX PORT */ +#define AUX_SIZE 0x01000000 +#define AUX_BASE 0xd2000000 + +#define FLASH1_START 0x00000000 /* FLASH BANK 1 */ +#define FLASH1_SIZE 0x01000000 +#define FLASH1_BASE 0xd3000000 + +#define FLASH2_START 0x10000000 /* FLASH BANK 2 */ +#define FLASH2_SIZE 0x01000000 +#define FLASH2_BASE 0xd4000000 #define ISA_START 0x20000000 /* ISA */ #define ISA_SIZE 0x20000000 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/io.h linux/include/asm-arm/arch-l7200/io.h --- v2.4.3/linux/include/asm-arm/arch-l7200/io.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-l7200/io.h Thu Apr 12 12:20:31 2001 @@ -3,8 +3,9 @@ * * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) * - * Modifications: + * Changelog: * 03-21-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h + * 08-31-2000 SJH Added in IO functions necessary for new drivers */ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H @@ -14,16 +15,49 @@ #define IO_SPACE_LIMIT 0xffffffff /* + * There are not real ISA nor PCI buses, so we fake it. + */ +#define __io_pci(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#define __ioaddr(p) __io_pci(p) + +/* + * Generic virtual read/write + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw" + : "=&r" (value) + : "r" (a)); + return value; +} + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__("str%?h %0, [%1, #0] @ putw" + : : "r" (value), "r" (a)); +} + +/* * Translated address IO functions * * IO address has already been translated to a virtual address */ -#define outb_t(v,p) (*(volatile unsigned char *)(p) = (v)) -#define inb_t(p) (*(volatile unsigned char *)(p)) -#define outw_t(v,p) (*(volatile unsigned int *)(p) = (v)) -#define inw_t(p) (*(volatile unsigned int *)(p)) -#define outl_t(v,p) (*(volatile unsigned long *)(p) = (v)) -#define inl_t(p) (*(volatile unsigned long *)(p)) +#define outb_t(v,p) (*(volatile unsigned char *)(p) = (v)) +#define inb_t(p) (*(volatile unsigned char *)(p)) +#define outw_t(v,p) (*(volatile unsigned int *)(p) = (v)) +#define inw_t(p) (*(volatile unsigned int *)(p)) +#define outl_t(v,p) (*(volatile unsigned long *)(p) = (v)) +#define inl_t(p) (*(volatile unsigned long *)(p)) /* * FIXME - These are to allow for linking. On all the other @@ -32,11 +66,13 @@ * macros will eventually become more involved. Use * with caution and don't be surprised by kernel oopses!!! */ -#define inb(p) inb_t(p) -#define inw(p) inw_t(p) -#define inl(p) inl_t(p) -#define outb(v,p) outb_t(v,p) -#define outw(v,p) outw_t(v,p) -#define outl(v,p) outl_t(v,p) +#define inb(p) inb_t(p) +#define inw(p) inw_t(p) +#define inl(p) inl_t(p) +#define outb(v,p) outb_t(v,p) +#define outw(v,p) outw_t(v,p) +#define outl(v,p) outl_t(v,p) + +#define __arch_ioremap __ioremap #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/irq.h linux/include/asm-arm/arch-l7200/irq.h --- v2.4.3/linux/include/asm-arm/arch-l7200/irq.h Mon May 15 12:00:33 2000 +++ linux/include/asm-arm/arch-l7200/irq.h Thu Apr 12 12:20:31 2001 @@ -10,6 +10,8 @@ * 05-05-2000 SJH Complete rewrite */ +#include <asm/arch/hardware.h> + /* * IRQ base register */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/irqs.h linux/include/asm-arm/arch-l7200/irqs.h --- v2.4.3/linux/include/asm-arm/arch-l7200/irqs.h Mon May 15 12:00:33 2000 +++ linux/include/asm-arm/arch-l7200/irqs.h Thu Apr 12 12:20:31 2001 @@ -7,6 +7,12 @@ * Changelog: * 01-02-2000 RS Create l7200 version * 03-28-2000 SJH Removed unused interrupt + * 07-28-2000 SJH Added pseudo-keyboard interrupt + */ + +/* + * NOTE: The second timer (Timer 2) is used as the keyboard + * interrupt when the keyboard driver is enabled. */ #define NR_IRQS 32 @@ -16,7 +22,7 @@ #define IRQ_DEBUG_RX 2 /* Comm Rx debug */ #define IRQ_DEBUG_TX 3 /* Comm Tx debug */ #define IRQ_GCTC1 4 /* Timer 1 */ -#define IRQ_GCTC2 5 /* Timer 2 */ +#define IRQ_GCTC2 5 /* Timer 2 / Keyboard */ #define IRQ_DMA 6 /* DMA controller */ #define IRQ_CLCD 7 /* Color LCD controller */ #define IRQ_SM_RX 8 /* Smart card */ @@ -40,6 +46,11 @@ #define IRQ_INT0 26 /* External active low interrupt */ #define IRQ_INT1 27 /* External active low interrupt */ #define IRQ_INT2 28 /* External active low interrupt */ -#define IRQ_INT3 29 /* External active low interrupt */ +#define IRQ_UCB1200 29 /* Interrupt generated by UCB1200*/ #define IRQ_BAT_LO 30 /* Low batery or external power */ #define IRQ_MEDIA_CHG 31 /* Media change interrupt */ + +/* + * This is the offset of the FIQ "IRQ" numbers + */ +#define FIQ_START 64 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/keyboard.h linux/include/asm-arm/arch-l7200/keyboard.h --- v2.4.3/linux/include/asm-arm/arch-l7200/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/keyboard.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-l7200/keyboard.h + * + * Keyboard driver definitions for LinkUp Systems L7200 architecture + * + * Copyright (C) 2000 Scott A McConnell (samcconn@cotw.com) + * Steve Hill (sjhill@cotw.com) + * + * 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. + * + * Changelog: + * 07-18-2000 SAM Created file + * 07-28-2000 SJH Complete rewrite + */ + +#include <asm/irq.h> + +/* + * Layout of L7200 keyboard registers + */ +struct KBD_Port { + unsigned int KBDR; + unsigned int KBDMR; + unsigned int KBSBSR; + unsigned int Reserved; + unsigned int KBKSR; +}; + +#define KBD_BASE IO_BASE_2 + 0x4000 +#define l7200kbd_hwregs ((volatile struct KBD_Port *) (KBD_BASE)) + +extern void l7200kbd_init_hw(void); +extern int l7200kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); + +#define kbd_setkeycode(sc,kc) (-EINVAL) +#define kbd_getkeycode(sc) (-EINVAL) + +#define kbd_translate(sc, kcp, rm) ({ *(kcp) = (sc); 1; }) +#define kbd_unexpected_up(kc) (0200) +#define kbd_leds(leds) do {} while (0) +#define kbd_init_hw() l7200kbd_init_hw() +#define kbd_sysrq_xlate do {} while (0) +#define kbd_disable_irq() disable_irq(IRQ_GCTC2) +#define kbd_enable_irq() enable_irq(IRQ_GCTC2) + +#define SYSRQ_KEY 13 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/pmpcon.h linux/include/asm-arm/arch-l7200/pmpcon.h --- v2.4.3/linux/include/asm-arm/arch-l7200/pmpcon.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/pmpcon.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,46 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/pmpcon.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * DC/DC converter register. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define PMPCON_OFF 0x00006000 /* Offset from IO_START_2. */ + +/* IO_START_2 and IO_BASE_2 are defined in hardware.h */ + +#define PMPCON_START (IO_START_2 + PMPCON_OFF) /* Physical address of reg. */ +#define PMPCON_BASE (IO_BASE_2 + PMPCON_OFF) /* Virtual address of reg. */ + + +#define PMPCON (*(volatile unsigned int *)(PMPCON_BASE)) + +#define PWM2_50CYCLE 0x800 +#define CONTRAST 0x9 + +#define PWM1H (CONTRAST) +#define PWM1L (CONTRAST << 4) + +#define PMPCON_VALUE (PWM2_50CYCLE | PWM1L | PWM1H) + +/* PMPCON = 0x811; // too light and fuzzy + * PMPCON = 0x844; + * PMPCON = 0x866; // better color poor depth + * PMPCON = 0x888; // Darker but better depth + * PMPCON = 0x899; // Darker even better depth + * PMPCON = 0x8aa; // too dark even better depth + * PMPCON = 0X8cc; // Way too dark + */ + +/* As CONTRAST value increases the greater the depth perception and + * the darker the colors. + */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/pmu.h linux/include/asm-arm/arch-l7200/pmu.h --- v2.4.3/linux/include/asm-arm/arch-l7200/pmu.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/pmu.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,125 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/pmu.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * Power Management Unit (PMU). + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define PMU_OFF 0x00050000 /* Offset from IO_START to the PMU registers. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define PMU_START (IO_START + PMU_OFF) /* Physical addr. of the PMU reg. */ +#define PMU_BASE (IO_BASE + PMU_OFF) /* Virtual addr. of the PMU reg. */ + + +/* Define the PMU registers for use by device drivers and the kernel. */ + +typedef struct { + unsigned int CURRENT; /* Current configuration register */ + unsigned int NEXT; /* Next configuration register */ + unsigned int reserved; + unsigned int RUN; /* Run configuration register */ + unsigned int COMM; /* Configuration command register */ + unsigned int SDRAM; /* SDRAM configuration bypass register */ +} pmu_interface; + +#define PMU ((volatile pmu_interface *)(PMU_BASE)) + + +/* Macro's for reading the common register fields. */ + +#define GET_TRANSOP(reg) ((reg >> 25) & 0x03) /* Bits 26-25 */ +#define GET_OSCEN(reg) ((reg >> 16) & 0x01) +#define GET_OSCMUX(reg) ((reg >> 15) & 0x01) +#define GET_PLLMUL(reg) ((reg >> 9) & 0x3f) /* Bits 14-9 */ +#define GET_PLLEN(reg) ((reg >> 8) & 0x01) +#define GET_PLLMUX(reg) ((reg >> 7) & 0x01) +#define GET_BCLK_DIV(reg) ((reg >> 3) & 0x03) /* Bits 4-3 */ +#define GET_SDRB_SEL(reg) ((reg >> 2) & 0x01) +#define GET_SDRF_SEL(reg) ((reg >> 1) & 0x01) +#define GET_FASTBUS(reg) (reg & 0x1) + +/* CFG_NEXT register */ + +#define CFG_NEXT_CLOCKRECOVERY ((PMU->NEXT >> 18) & 0x7f) /* Bits 24-18 */ +#define CFG_NEXT_INTRET ((PMU->NEXT >> 17) & 0x01) +#define CFG_NEXT_SDR_STOP ((PMU->NEXT >> 6) & 0x01) +#define CFG_NEXT_SYSCLKEN ((PMU->NEXT >> 5) & 0x01) + +/* Useful field values that can be used to construct the + * CFG_NEXT and CFG_RUN registers. + */ + +#define TRANSOP_NOP 0<<25 /* NOCHANGE_NOSTALL */ +#define NOCHANGE_STALL 1<<25 +#define CHANGE_NOSTALL 2<<25 +#define CHANGE_STALL 3<<25 + +#define INTRET 1<<17 +#define OSCEN 1<<16 +#define OSCMUX 1<<15 + +/* PLL frequencies */ + +#define PLLMUL_0 0<<9 /* 3.6864 MHz */ +#define PLLMUL_1 1<<9 /* ?????? MHz */ +#define PLLMUL_5 5<<9 /* 18.432 MHz */ +#define PLLMUL_10 10<<9 /* 36.864 MHz */ +#define PLLMUL_18 18<<9 /* ?????? MHz */ +#define PLLMUL_20 20<<9 /* 73.728 MHz */ +#define PLLMUL_32 32<<9 /* ?????? MHz */ +#define PLLMUL_35 35<<9 /* 129.024 MHz */ +#define PLLMUL_36 36<<9 /* ?????? MHz */ +#define PLLMUL_39 39<<9 /* ?????? MHz */ +#define PLLMUL_40 40<<9 /* 147.456 MHz */ + +/* Clock recovery times */ + +#define CRCLOCK_1 1<<18 +#define CRCLOCK_2 2<<18 +#define CRCLOCK_4 4<<18 +#define CRCLOCK_8 8<<18 +#define CRCLOCK_16 16<<18 +#define CRCLOCK_32 32<<18 +#define CRCLOCK_63 63<<18 +#define CRCLOCK_127 127<<18 + +#define PLLEN 1<<8 +#define PLLMUX 1<<7 +#define SDR_STOP 1<<6 +#define SYSCLKEN 1<<5 + +#define BCLK_DIV_4 2<<3 +#define BCLK_DIV_2 1<<3 +#define BCLK_DIV_1 0<<3 + +#define SDRB_SEL 1<<2 +#define SDRF_SEL 1<<1 +#define FASTBUS 1<<0 + + +/* CFG_SDRAM */ + +#define SDRREFFQ 1<<0 /* Only if SDRSTOPRQ is not set. */ +#define SDRREFACK 1<<1 /* Read-only */ +#define SDRSTOPRQ 1<<2 /* Only if SDRREFFQ is not set. */ +#define SDRSTOPACK 1<<3 /* Read-only */ +#define PICEN 1<<4 /* Enable Co-procesor */ +#define PICTEST 1<<5 + +#define GET_SDRREFFQ ((PMU->SDRAM >> 0) & 0x01) +#define GET_SDRREFACK ((PMU->SDRAM >> 1) & 0x01) /* Read-only */ +#define GET_SDRSTOPRQ ((PMU->SDRAM >> 2) & 0x01) +#define GET_SDRSTOPACK ((PMU->SDRAM >> 3) & 0x01) /* Read-only */ +#define GET_PICEN ((PMU->SDRAM >> 4) & 0x01) +#define GET_PICTEST ((PMU->SDRAM >> 5) & 0x01) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/serial.h linux/include/asm-arm/arch-l7200/serial.h --- v2.4.3/linux/include/asm-arm/arch-l7200/serial.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/serial.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,39 @@ +/* + * linux/include/asm-arm/arch-l7200/serial.h + * + * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 03-20-2000 SJH Created + * 03-26-2000 SJH Added flags for serial ports + * 03-27-2000 SJH Corrected BASE_BAUD value + * 04-14-2000 RS Made register addr dependent on IO_BASE + * 05-03-2000 SJH Complete rewrite + * 05-09-2000 SJH Stripped out architecture specific serial stuff + * and placed it in a separate file + * 07-28-2000 SJH Moved base baud rate variable + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +/* + * This assumes you have a 3.6864 MHz clock for your UART. + */ +#define BASE_BAUD 3686400 + +/* + * Standard COM flags + */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#define RS_TABLE_SIZE 2 + +#define STD_SERIAL_PORT_DEFNS \ + /* MAGIC UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, UART1_BASE, IRQ_UART_1, STD_COM_FLAGS }, /* ttyLU0 */ \ + { 0, BASE_BAUD, UART2_BASE, IRQ_UART_2, STD_COM_FLAGS }, /* ttyLU1 */ \ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/sib.h linux/include/asm-arm/arch-l7200/sib.h --- v2.4.3/linux/include/asm-arm/arch-l7200/sib.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/sib.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,119 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/sib.h + * + * Registers and helper functions for the Serial Interface Bus. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define SIB_OFF 0x00040000 /* Offset from IO_START to the SIB reg's. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define SIB_START (IO_START + SIB_OFF) /* Physical addr of the SIB reg. */ +#define SIB_BASE (IO_BASE + SIB_OFF) /* Virtual addr of the SIB reg. */ + +/* Offsets from the start of the SIB for all the registers. */ + +/* Define the SIB registers for use by device drivers and the kernel. */ + +typedef struct +{ + unsigned int MCCR; /* SIB Control Register Offset: 0x00 */ + unsigned int RES1; /* Reserved Offset: 0x04 */ + unsigned int MCDR0; /* SIB Data Register 0 Offset: 0x08 */ + unsigned int MCDR1; /* SIB Data Register 1 Offset: 0x0c */ + unsigned int MCDR2; /* SIB Data Register 2 (UCB1x00) Offset: 0x10 */ + unsigned int RES2; /* Reserved Offset: 0x14 */ + unsigned int MCSR; /* SIB Status Register Offset: 0x18 */ +} SIB_Interface; + +#define SIB ((volatile SIB_Interface *) (SIB_BASE)) + +/* MCCR */ + +#define INTERNAL_FREQ 9216000 /* Hertz */ +#define AUDIO_FREQ 5000 /* Hertz */ +#define TELECOM_FREQ 5000 /* Hertz */ + +#define AUDIO_DIVIDE (INTERNAL_FREQ / (32 * AUDIO_FREQ)) +#define TELECOM_DIVIDE (INTERNAL_FREQ / (32 * TELECOM_FREQ)) + +#define MCCR_ASD57 AUDIO_DIVIDE +#define MCCR_TSD57 (TELECOM_DIVIDE << 8) +#define MCCR_MCE (1 << 16) /* SIB enable */ +#define MCCR_ECS (1 << 17) /* External Clock Select */ +#define MCCR_ADM (1 << 18) /* A/D Data Sampling */ +#define MCCR_PMC (1 << 26) /* PIN Multiplexer Control */ + + +#define GET_ASD ((SIB->MCCR >> 0) & 0x3f) /* Audio Sample Rate Div. */ +#define GET_TSD ((SIB->MCCR >> 8) & 0x3f) /* Telcom Sample Rate Div. */ +#define GET_MCE ((SIB->MCCR >> 16) & 0x01) /* SIB Enable */ +#define GET_ECS ((SIB->MCCR >> 17) & 0x01) /* External Clock Select */ +#define GET_ADM ((SIB->MCCR >> 18) & 0x01) /* A/D Data Sampling Mode */ +#define GET_TTM ((SIB->MCCR >> 19) & 0x01) /* Telco Trans. FIFO I mask */ +#define GET_TRM ((SIB->MCCR >> 20) & 0x01) /* Telco Recv. FIFO I mask */ +#define GET_ATM ((SIB->MCCR >> 21) & 0x01) /* Audio Trans. FIFO I mask */ +#define GET_ARM ((SIB->MCCR >> 22) & 0x01) /* Audio Recv. FIFO I mask */ +#define GET_LBM ((SIB->MCCR >> 23) & 0x01) /* Loop Back Mode */ +#define GET_ECP ((SIB->MCCR >> 24) & 0x03) /* Extern. Clck Prescale sel */ +#define GET_PMC ((SIB->MCCR >> 26) & 0x01) /* PIN Multiplexer Control */ +#define GET_ERI ((SIB->MCCR >> 27) & 0x01) /* External Read Interrupt */ +#define GET_EWI ((SIB->MCCR >> 28) & 0x01) /* External Write Interrupt */ + +/* MCDR0 */ + +#define AUDIO_RECV ((SIB->MCDR0 >> 4) & 0xfff) +#define AUDIO_WRITE(v) ((SIB->MCDR0 = (v & 0xfff) << 4)) + +/* MCDR1 */ + +#define TELECOM_RECV ((SIB->MCDR1 >> 2) & 032fff) +#define TELECOM_WRITE(v) ((SIB->MCDR1 = (v & 0x3fff) << 2)) + + +/* MCSR */ + +#define MCSR_ATU (1 << 4) /* Audio Transmit FIFO Underrun */ +#define MCSR_ARO (1 << 5) /* Audio Receive FIFO Underrun */ +#define MCSR_TTU (1 << 6) /* TELECOM Transmit FIFO Underrun */ +#define MCSR_TRO (1 << 7) /* TELECOM Receive FIFO Underrun */ + +#define MCSR_CLEAR_UNDERUN_BITS (MCSR_ATU | MCSR_ARO | MCSR_TTU | MCSR_TRO) + + +#define GET_ATS ((SIB->MCSR >> 0) & 0x01) /* Audio Transmit FIFO Service Req*/ +#define GET_ARS ((SIB->MCSR >> 1) & 0x01) /* Audio Recv FIFO Service Request*/ +#define GET_TTS ((SIB->MCSR >> 2) & 0x01) /* TELECOM Transmit FIFO Flag */ +#define GET_TRS ((SIB->MCSR >> 3) & 0x01) /* TELECOM Recv FIFO Service Req. */ +#define GET_ATU ((SIB->MCSR >> 4) & 0x01) /* Audio Transmit FIFO Underrun */ +#define GET_ARO ((SIB->MCSR >> 5) & 0x01) /* Audio Receive FIFO Underrun */ +#define GET_TTU ((SIB->MCSR >> 6) & 0x01) /* TELECOM Transmit FIFO Underrun */ +#define GET_TRO ((SIB->MCSR >> 7) & 0x01) /* TELECOM Receive FIFO Underrun */ +#define GET_ANF ((SIB->MCSR >> 8) & 0x01) /* Audio Transmit FIFO not full */ +#define GET_ANE ((SIB->MCSR >> 9) & 0x01) /* Audio Receive FIFO not empty */ +#define GET_TNF ((SIB->MCSR >> 10) & 0x01) /* Telecom Transmit FIFO not full */ +#define GET_TNE ((SIB->MCSR >> 11) & 0x01) /* Telecom Receive FIFO not empty */ +#define GET_CWC ((SIB->MCSR >> 12) & 0x01) /* Codec Write Complete */ +#define GET_CRC ((SIB->MCSR >> 13) & 0x01) /* Codec Read Complete */ +#define GET_ACE ((SIB->MCSR >> 14) & 0x01) /* Audio Codec Enabled */ +#define GET_TCE ((SIB->MCSR >> 15) & 0x01) /* Telecom Codec Enabled */ + +/* MCDR2 */ + +#define MCDR2_rW (1 << 16) + +#define WRITE_MCDR2(reg, data) (SIB->MCDR2 =((reg<<17)|MCDR2_rW|(data&0xffff))) +#define MCDR2_WRITE_COMPLETE GET_CWC + +#define INITIATE_MCDR2_READ(reg) (SIB->MCDR2 = (reg << 17)) +#define MCDR2_READ_COMPLETE GET_CRC +#define MCDR2_READ (SIB->MCDR2 & 0xffff) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/sys-clock.h linux/include/asm-arm/arch-l7200/sys-clock.h --- v2.4.3/linux/include/asm-arm/arch-l7200/sys-clock.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-l7200/sys-clock.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,67 @@ +/****************************************************************************/ +/* + * linux/include/asm-arm/arch-l7200/sys-clock.h + * + * Registers and helper functions for the L7200 Link-Up Systems + * System clocks. + * + * (C) Copyright 2000, S A McConnell (samcconn@cotw.com) + * + * 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. + */ + +/****************************************************************************/ + +#define SYS_CLOCK_OFF 0x00050030 /* Offset from IO_START. */ + +/* IO_START and IO_BASE are defined in hardware.h */ + +#define SYS_CLOCK_START (IO_START + SYS_CLCOK_OFF) /* Physical address */ +#define SYS_CLOCK_BASE (IO_BASE + SYS_CLOCK_OFF) /* Virtual address */ + +/* Define the interface to the SYS_CLOCK */ + +typedef struct +{ + unsigned int ENABLE; + unsigned int ESYNC; + unsigned int SELECT; +} sys_clock_interface; + +#define SYS_CLOCK ((volatile sys_clock_interface *)(SYS_CLOCK_BASE)) + +//#define CLOCK_EN (*(volatile unsigned long *)(PMU_BASE+CLOCK_EN_OFF)) +//#define CLOCK_ESYNC (*(volatile unsigned long *)(PMU_BASE+CLOCK_ESYNC_OFF)) +//#define CLOCK_SEL (*(volatile unsigned long *)(PMU_BASE+CLOCK_SEL_OFF)) + +/* SYS_CLOCK -> ENABLE */ + +#define SYN_EN 1<<0 +#define B18M_EN 1<<1 +#define CLK3M6_EN 1<<2 +#define BUART_EN 1<<3 +#define CLK18MU_EN 1<<4 +#define FIR_EN 1<<5 +#define MIRN_EN 1<<6 +#define UARTM_EN 1<<7 +#define SIBADC_EN 1<<8 +#define ALTD_EN 1<<9 +#define CLCLK_EN 1<<10 + +/* SYS_CLOCK -> SELECT */ + +#define CLK18M_DIV 1<<0 +#define MIR_SEL 1<<1 +#define SSP_SEL 1<<4 +#define MM_DIV 1<<5 +#define MM_SEL 1<<6 +#define ADC_SEL_2 0<<7 +#define ADC_SEL_4 1<<7 +#define ADC_SEL_8 3<<7 +#define ADC_SEL_16 7<<7 +#define ADC_SEL_32 0x0f<<7 +#define ADC_SEL_64 0x1f<<7 +#define ADC_SEL_128 0x3f<<7 +#define ALTD_SEL 1<<13 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/system.h linux/include/asm-arm/arch-l7200/system.h --- v2.4.3/linux/include/asm-arm/arch-l7200/system.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-l7200/system.h Thu Apr 12 12:20:31 2001 @@ -14,9 +14,8 @@ static void arch_idle(void) { - while (!current->need_resched && !hlt_counter) { - cpu_do_idle(IDLE_WAIT_SLOW); - } + /* fixme: this needs to be cleaned up (converted from ASM code) --rmk */ + *(unsigned long *)(IO_BASE + 0x50004) = 1; /* idle mode */ } extern inline void arch_reset(char mode) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-l7200/time.h linux/include/asm-arm/arch-l7200/time.h --- v2.4.3/linux/include/asm-arm/arch-l7200/time.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-l7200/time.h Thu Apr 12 12:20:31 2001 @@ -40,7 +40,7 @@ #define RTC_EN_STWDOG 0x08 /* Enable watchdog */ /* - * Handler for timer interrupt + * Handler for RTC timer interrupt */ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -50,7 +50,7 @@ } /* - * Set up timer interrupt, and return the current time in seconds. + * Set up RTC timer interrupt, and return the current time in seconds. */ extern __inline__ void setup_timer(void) { diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h --- v2.4.3/linux/include/asm-arm/arch-rpc/hardware.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-rpc/hardware.h Thu Apr 12 12:20:31 2001 @@ -43,66 +43,27 @@ #define FLUSH_BASE 0xdf000000 #define UNCACHEABLE_ADDR 0xdf010000 - -#ifndef __ASSEMBLY__ - -/* - * for use with inb/outb - */ -#define IO_VIDC_AUDIO_BASE 0x80140000 -#define IO_VIDC_BASE 0x80100000 -#define IO_IOMD_BASE 0x80080000 -#define IOC_BASE 0x80080000 - -#define IO_EC_EASI_BASE 0x81400000 -#define IO_EC_IOC4_BASE 0x8009c000 -#define IO_EC_IOC_BASE 0x80090000 -#define IO_EC_MEMC8_BASE 0x8000ac00 -#define IO_EC_MEMC_BASE 0x80000000 - -/* - * IO definitions - */ -#define EXPMASK_BASE ((volatile unsigned char *)0xe0360000) -#define IOEB_BASE ((volatile unsigned char *)0xe0350050) -#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000) -#define PCIO_BASE 0xe0010000 - /* - * Offsets from RAM base + * IO Addresses */ -#define PARAMS_OFFSET 0x0100 - -/* - * RAM definitions - */ -#define GET_MEMORY_END(p) (PAGE_OFFSET + p->u1.s.page_size * \ - (p->u1.s.pages_in_bank[0] + \ - p->u1.s.pages_in_bank[1] + \ - p->u1.s.pages_in_bank[2] + \ - p->u1.s.pages_in_bank[3])) - -#define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET) -#define FLUSH_BASE_PHYS 0x00000000 /* ROM */ - -#else - -#define VIDC_SND_BASE 0xe0500000 #define VIDC_BASE 0xe0400000 +#define EXPMASK_BASE 0xe0360000 #define IOMD_BASE 0xe0200000 #define IOC_BASE 0xe0200000 -#define PCIO_FLOPPYDMABASE 0xe002a000 #define PCIO_BASE 0xe0010000 +#define FLOPPYDMA_BASE 0xe002a000 -#endif +#define FLUSH_BASE_PHYS 0x00000000 /* ROM */ + +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) -#ifndef __ASSEMBLY__ -#define __EXPMASK(offset) (((volatile unsigned char *)EXPMASK_BASE)[offset]) -#else -#define __EXPMASK(offset) offset -#endif +#define IO_EC_EASI_BASE 0x81400000 +#define IO_EC_IOC4_BASE 0x8009c000 +#define IO_EC_IOC_BASE 0x80090000 +#define IO_EC_MEMC8_BASE 0x8000ac00 +#define IO_EC_MEMC_BASE 0x80000000 -#define EXPMASK_STATUS __EXPMASK(0x00) -#define EXPMASK_ENABLE __EXPMASK(0x04) +#define EXPMASK_STATUS (EXPMASK_BASE + 0x00) +#define EXPMASK_ENABLE (EXPMASK_BASE + 0x04) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h --- v2.4.3/linux/include/asm-arm/arch-rpc/irq.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-rpc/irq.h Thu Apr 12 12:20:31 2001 @@ -12,129 +12,100 @@ * 22-08-1998 RMK Restructured IRQ routines */ #include <asm/hardware/iomd.h> +#include <asm/io.h> #define fixup_irq(x) (x) static void rpc_mask_irq_ack_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]\n" -" strb %1, [%3]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)), - "r" (ioaddr(IOMD_IRQCLRA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); + iomd_writeb(mask, IOMD_IRQCLRA); } static void rpc_mask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val & ~mask, IOMD_IRQMASKA); } static void rpc_unmask_irq_a(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA))); + mask = 1 << irq; + val = iomd_readb(IOMD_IRQMASKA); + iomd_writeb(val | mask, IOMD_IRQMASKA); } static void rpc_mask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val & ~mask, IOMD_IRQMASKB); } static void rpc_unmask_irq_b(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_IRQMASKB); + iomd_writeb(val | mask, IOMD_IRQMASKB); } static void rpc_mask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val & ~mask, IOMD_DMAMASK); } static void rpc_unmask_irq_dma(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_DMAMASK); + iomd_writeb(val | mask, IOMD_DMAMASK); } static void rpc_mask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" bic %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val & ~mask, IOMD_FIQMASK); } static void rpc_unmask_irq_fiq(unsigned int irq) { - unsigned int temp; + unsigned int val, mask; - __asm__ __volatile__( - "ldrb %0, [%2]\n" -" orr %0, %0, %1\n" -" strb %0, [%2]" - : "=&r" (temp) - : "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK))); + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val | mask, IOMD_FIQMASK); } static __inline__ void irq_init_irq(void) { - extern void ecard_disableirq(unsigned int irq); - extern void ecard_enableirq(unsigned int irq); int irq; - outb(0, IOMD_IRQMASKA); - outb(0, IOMD_IRQMASKB); - outb(0, IOMD_FIQMASK); - outb(0, IOMD_DMAMASK); + iomd_writeb(0, IOMD_IRQMASKA); + iomd_writeb(0, IOMD_IRQMASKB); + iomd_writeb(0, IOMD_FIQMASK); + iomd_writeb(0, IOMD_DMAMASK); for (irq = 0; irq < NR_IRQS; irq++) { switch (irq) { @@ -156,19 +127,14 @@ irq_desc[irq].unmask = rpc_unmask_irq_b; break; - case 16 ... 21: - irq_desc[irq].valid = 1; + case 16 ... 19: + case 21: irq_desc[irq].noautoenable = 1; + case 20: + irq_desc[irq].valid = 1; irq_desc[irq].mask_ack = rpc_mask_irq_dma; irq_desc[irq].mask = rpc_mask_irq_dma; irq_desc[irq].unmask = rpc_unmask_irq_dma; - break; - - case 32 ... 39: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = ecard_disableirq; - irq_desc[irq].mask = ecard_disableirq; - irq_desc[irq].unmask = ecard_enableirq; break; case 64 ... 71: diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h --- v2.4.3/linux/include/asm-arm/arch-rpc/system.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-rpc/system.h Thu Apr 12 12:20:31 2001 @@ -35,11 +35,7 @@ extern __inline__ void arch_reset(char mode) { - extern void ecard_reset(int card); - - ecard_reset(-1); - - outb(0, IOMD_ROMCR0); + iomd_writeb(0, IOMD_ROMCR0); /* * Jump into the ROM diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/SA-1100.h linux/include/asm-arm/arch-sa1100/SA-1100.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/SA-1100.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-sa1100/SA-1100.h Thu Apr 12 12:20:31 2001 @@ -271,6 +271,7 @@ #define UDCCR_UDD 0x00000001 /* UDC Disable */ #define UDCCR_UDA 0x00000002 /* UDC Active (read) */ +#define UDCCR_RESIM 0x00000004 /* Resume Interrupt Mask, per errata */ #define UDCCR_EIM 0x00000008 /* End-point 0 Interrupt Mask */ /* (disable) */ #define UDCCR_RIM 0x00000010 /* Receive Interrupt Mask */ @@ -279,6 +280,7 @@ /* (disable) */ #define UDCCR_SRM 0x00000040 /* Suspend/Resume interrupt Mask */ /* (disable) */ +#define UDCCR_SUSIM UDCCR_SRM /* Per errata, SRM just masks suspend */ #define UDCCR_REM 0x00000080 /* REset interrupt Mask (disable) */ #define UDCAR_ADD Fld (7, 0) /* function ADDress */ @@ -502,6 +504,32 @@ #define Ser3UTSR1 /* Ser. port 3 UART Status Reg. 1 */ \ (*((volatile Word *) io_p2v (_Ser3UTSR1))) +#elif LANGUAGE == Assembly +#define Ser1UTCR0 ( io_p2v (_Ser1UTCR0)) +#define Ser1UTCR1 ( io_p2v (_Ser1UTCR1)) +#define Ser1UTCR2 ( io_p2v (_Ser1UTCR2)) +#define Ser1UTCR3 ( io_p2v (_Ser1UTCR3)) +#define Ser1UTDR ( io_p2v (_Ser1UTDR)) +#define Ser1UTSR0 ( io_p2v (_Ser1UTSR0)) +#define Ser1UTSR1 ( io_p2v (_Ser1UTSR1)) + +#define Ser2UTCR0 ( io_p2v (_Ser2UTCR0)) +#define Ser2UTCR1 ( io_p2v (_Ser2UTCR1)) +#define Ser2UTCR2 ( io_p2v (_Ser2UTCR2)) +#define Ser2UTCR3 ( io_p2v (_Ser2UTCR3)) +#define Ser2UTCR4 ( io_p2v (_Ser2UTCR4)) +#define Ser2UTDR ( io_p2v (_Ser2UTDR)) +#define Ser2UTSR0 ( io_p2v (_Ser2UTSR0)) +#define Ser2UTSR1 ( io_p2v (_Ser2UTSR1)) + +#define Ser3UTCR0 ( io_p2v (_Ser3UTCR0)) +#define Ser3UTCR1 ( io_p2v (_Ser3UTCR1)) +#define Ser3UTCR2 ( io_p2v (_Ser3UTCR2)) +#define Ser3UTCR3 ( io_p2v (_Ser3UTCR3)) +#define Ser3UTDR ( io_p2v (_Ser3UTDR)) +#define Ser3UTSR0 ( io_p2v (_Ser3UTSR0)) +#define Ser3UTSR1 ( io_p2v (_Ser3UTSR1)) + #endif /* LANGUAGE == C */ #define UTCR0_PE 0x00000001 /* Parity Enable */ @@ -1229,6 +1257,17 @@ (*((volatile Word *) io_p2v (_PGSR))) #define POSR /* PM Oscillator Status Reg. */ \ (*((volatile Word *) io_p2v (_POSR))) + +#elif LANGUAGE == Assembly +#define PMCR (io_p2v (_PMCR)) +#define PSSR (io_p2v (_PSSR)) +#define PSPR (io_p2v (_PSPR)) +#define PWER (io_p2v (_PWER)) +#define PCFR (io_p2v (_PCFR)) +#define PPCR (io_p2v (_PPCR)) +#define PGSR (io_p2v (_PGSR)) +#define POSR (io_p2v (_POSR)) + #endif /* LANGUAGE == C */ #define PMCR_SF 0x00000001 /* Sleep Force (set only) */ @@ -1481,6 +1520,17 @@ (*((volatile Word *) io_p2v (_GEDR))) #define GAFR /* GPIO Alternate Function Reg. */ \ (*((volatile Word *) io_p2v (_GAFR))) +#elif LANGUAGE == Assembly + +#define GPLR (io_p2v (_GPLR)) +#define GPDR (io_p2v (_GPDR)) +#define GPSR (io_p2v (_GPSR)) +#define GPCR (io_p2v (_GPCR)) +#define GRER (io_p2v (_GRER)) +#define GFER (io_p2v (_GFER)) +#define GEDR (io_p2v (_GEDR)) +#define GAFR (io_p2v (_GAFR)) + #endif /* LANGUAGE == C */ #define GPIO_MIN (0) @@ -1784,6 +1834,11 @@ #define MDCAS0 (MDCAS [0]) /* DRAM CAS shift reg. 0 */ #define MDCAS1 (MDCAS [1]) /* DRAM CAS shift reg. 1 */ #define MDCAS2 (MDCAS [2]) /* DRAM CAS shift reg. 2 */ + +#elif LANGUAGE == Assembly + +#define MDCNFG (io_p2v(_MDCNFG)) + #endif /* LANGUAGE == C */ /* SA1100 MDCNFG values */ @@ -1870,6 +1925,13 @@ ((volatile Word *) io_p2v (_MSC (0))) #define MSC0 (MSC [0]) /* Static memory Control reg. 0 */ #define MSC1 (MSC [1]) /* Static memory Control reg. 1 */ + +#elif LANGUAGE == Assembly + +#define MSC0 io_p2v(0xa0000010) +#define MSC1 io_p2v(0xa0000014) +#define MSC2 io_p2v(0xa000002c) + #endif /* LANGUAGE == C */ #define MSC_Bnk(Nb) /* static memory Bank [0..3] */ \ @@ -1895,32 +1957,32 @@ /* First access - 1(.5) [Tmem] */ #define MSC_1stRdAcc(Tcpu) /* 1st Read Access time (burst */ \ /* static memory) [3..65 Tcpu] */ \ - (((Tcpu) - 3)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 3)/2) << FShft (MSC_RDF)) #define MSC_Ceil1stRdAcc(Tcpu) /* Ceil. of 1stRdAcc [3..65 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDF)) #define MSC_RdAcc(Tcpu) /* Read Access time (non-burst */ \ /* static memory) [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDF)) #define MSC_CeilRdAcc(Tcpu) /* Ceil. of RdAcc [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MSC_RDF)) + ((((Tcpu) - 1)/2) << FShft (MSC_RDF)) #define MSC_RDN Fld (5, 8) /* ROM/static memory read Delay */ /* Next access - 1 [Tmem] */ #define MSC_NxtRdAcc(Tcpu) /* Next Read Access time (burst */ \ /* static memory) [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDN)) #define MSC_CeilNxtRdAcc(Tcpu) /* Ceil. of NxtRdAcc [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 1)/2) << FShft (MSC_RDN)) #define MSC_WrAcc(Tcpu) /* Write Access time (non-burst */ \ /* static memory) [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 2)/2) << FShft (MSC_RDN)) #define MSC_CeilWrAcc(Tcpu) /* Ceil. of WrAcc [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MSC_RDN)) + ((((Tcpu) - 1)/2) << FShft (MSC_RDN)) #define MSC_RRR Fld (3, 13) /* ROM/static memory RecoveRy */ /* time/2 [Tmem] */ #define MSC_Rec(Tcpu) /* Recovery time [0..28 Tcpu] */ \ - ((Tcpu)/4 << FShft (MSC_RRR)) + (((Tcpu)/4) << FShft (MSC_RRR)) #define MSC_CeilRec(Tcpu) /* Ceil. of Rec [0..28 Tcpu] */ \ - (((Tcpu) + 3)/4 << FShft (MSC_RRR)) + ((((Tcpu) + 3)/4) << FShft (MSC_RRR)) /* @@ -1955,20 +2017,20 @@ #define MECR_BSIO Fld (5, 0) /* BCLK Select I/O - 1 [Tmem] */ #define MECR_IOClk(Tcpu) /* I/O Clock [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MECR_BSIO)) + ((((Tcpu) - 2)/2) << FShft (MECR_BSIO)) #define MECR_CeilIOClk(Tcpu) /* Ceil. of IOClk [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MECR_BSIO)) + ((((Tcpu) - 1)/2) << FShft (MECR_BSIO)) #define MECR_BSA Fld (5, 5) /* BCLK Select Attribute - 1 */ /* [Tmem] */ #define MECR_AttrClk(Tcpu) /* Attribute Clock [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MECR_BSA)) + ((((Tcpu) - 2)/2) << FShft (MECR_BSA)) #define MECR_CeilAttrClk(Tcpu) /* Ceil. of AttrClk [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MECR_BSA)) + ((((Tcpu) - 1)/2) << FShft (MECR_BSA)) #define MECR_BSM Fld (5, 10) /* BCLK Select Memory - 1 [Tmem] */ #define MECR_MemClk(Tcpu) /* Memory Clock [2..64 Tcpu] */ \ - (((Tcpu) - 2)/2 << FShft (MECR_BSM)) + ((((Tcpu) - 2)/2) << FShft (MECR_BSM)) #define MECR_CeilMemClk(Tcpu) /* Ceil. of MemClk [2..64 Tcpu] */ \ - (((Tcpu) - 1)/2 << FShft (MECR_BSM)) + ((((Tcpu) - 1)/2) << FShft (MECR_BSM)) /* * On SA1110 only @@ -1981,6 +2043,10 @@ #define MDREFR \ (*((volatile Word *) io_p2v (_MDREFR))) +#elif LANGUAGE == Assembly + +#define MDREFR (io_p2v(_MDREFR)) + #endif /* LANGUAGE == C */ #define MDREFR_TRASR Fld (4, 0) @@ -2456,18 +2522,18 @@ (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \ DDAR_Ser3UARTRc + DDAR_DevAdd (_Ser3UTDR)) #define DDAR_Ser4MCP0Wr /* Ser. port 4 MCP 0 Write (audio) */ \ - (DDAR_DevWr + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP0Tr + DDAR_DevAdd (_Ser4MCDR0)) #define DDAR_Ser4MCP0Rd /* Ser. port 4 MCP 0 Read (audio) */ \ - (DDAR_DevRd + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP0Rc + DDAR_DevAdd (_Ser4MCDR0)) #define DDAR_Ser4MCP1Wr /* Ser. port 4 MCP 1 Write */ \ /* (telecom) */ \ - (DDAR_DevWr + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP1Tr + DDAR_DevAdd (_Ser4MCDR1)) #define DDAR_Ser4MCP1Rd /* Ser. port 4 MCP 1 Read */ \ /* (telecom) */ \ - (DDAR_DevRd + DDAR_Brst8 + DDAR_16BitDev + \ + (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ DDAR_Ser4MCP1Rc + DDAR_DevAdd (_Ser4MCDR1)) #define DDAR_Ser4SSPWr /* Ser. port 4 SSP Write (16 bits) */ \ (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/assabet.h linux/include/asm-arm/arch-sa1100/assabet.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/assabet.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-sa1100/assabet.h Thu Apr 12 12:20:31 2001 @@ -32,7 +32,7 @@ #define BCR (*(volatile unsigned int *)(BCR_BASE)) #define BCR_DB1110 (0x00A07410) -#define BCR_DB1111 (0x00A07462) +#define BCR_DB1111 (0x00A074E2) #define BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */ #define BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */ @@ -89,6 +89,7 @@ #define IRQ_GPIO_CF_IRQ IRQ_GPIO21 #define IRQ_GPIO_CF_CD IRQ_GPIO22 +#define IRQ_GPIO_MBREQ IRQ_GPIO22 #define IRQ_GPIO_UCB1300_IRQ IRQ_GPIO23 #define IRQ_GPIO_CF_BVD2 IRQ_GPIO24 #define IRQ_GPIO_CF_BVD1 IRQ_GPIO25 @@ -139,6 +140,9 @@ #define IRR_ETHERNET (1<<0) #define IRR_USAR (1<<1) #define IRR_SA1111 (1<<2) + +#define AUD_SEL_1341 (1<<0) +#define AUD_MUTE_1341 (1<<1) #define NCR_GP01_OFF (1<<0) #define NCR_TP_PWR_EN (1<<1) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/bitsy.h linux/include/asm-arm/arch-sa1100/bitsy.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/bitsy.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-sa1100/bitsy.h Thu Apr 12 12:20:31 2001 @@ -1,6 +1,9 @@ #ifndef _INCLUDE_BITSY_H_ #define _INCLUDE_BITSY_H_ +#define GPIO_BITSY_NPOWER_BUTTON GPIO_GPIO (0) +#define GPIO_BITSY_ACTION_BUTTON GPIO_GPIO (18) + #define GPIO_BITSY_PCMCIA_CD0 GPIO_GPIO (17) #define GPIO_BITSY_PCMCIA_CD1 GPIO_GPIO (10) #define GPIO_BITSY_PCMCIA_IRQ0 GPIO_GPIO (21) @@ -15,6 +18,9 @@ #define GPIO_BITSY_L3_MODE GPIO_GPIO (15) + +#define IRQ_GPIO_BITSY_NPOWER_BUTTON IRQ_GPIO0 +#define IRQ_GPIO_BITSY_ACTION_BUTTON IRQ_GPIO18 #define IRQ_GPIO_BITSY_PCMCIA_CD0 IRQ_GPIO17 #define IRQ_GPIO_BITSY_PCMCIA_CD1 IRQ_GPIO10 #define IRQ_GPIO_BITSY_PCMCIA_IRQ0 IRQ_GPIO21 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/dma.h linux/include/asm-arm/arch-sa1100/dma.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/dma.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-sa1100/dma.h Thu Apr 12 12:20:31 2001 @@ -1,12 +1,107 @@ /* * linux/include/asm-arm/arch-sa1100/dma.h + * + * Generic SA1100 DMA support + * + * Copyright (C) 2000 Nicolas Pitre + * */ + #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H +#include <linux/config.h> +#include "hardware.h" + + +/* + * This is the maximum DMA address that can be DMAd to. + */ #define MAX_DMA_ADDRESS 0xffffffff -/* No DMA (strictly, a lie :-) ) */ + +/* + * The regular generic DMA interface is inappropriate for the + * SA1100 DMA model. None of the SA1100 specific drivers using + * DMA are portable anyway so it's pointless to try to twist the + * regular DMA API to accommodate them. + */ #define MAX_DMA_CHANNELS 0 + + +/* + * The SA1100 has six internal DMA channels. + */ +#define SA1100_DMA_CHANNELS 6 + + +/* + * The SA-1111 SAC has two DMA channels. + */ +#define SA1111_SAC_DMA_CHANNELS 2 +#define SA1111_SAC_XMT_CHANNEL 0 +#define SA1111_SAC_RCV_CHANNEL 1 + + +/* + * The SA-1111 SAC channels will reside in the same index space as + * the built-in SA-1100 channels, and will take on the next available + * identifiers after the 1100. + */ +#define SA1111_SAC_DMA_BASE SA1100_DMA_CHANNELS + +#ifdef CONFIG_SA1111 +# define MAX_SA1100_DMA_CHANNELS (SA1100_DMA_CHANNELS + SA1111_SAC_DMA_CHANNELS) +#else +# define MAX_SA1100_DMA_CHANNELS SA1100_DMA_CHANNELS +#endif + + +/* + * All possible SA1100 devices a DMA channel can be attached to. + */ +typedef enum { + DMA_Ser0UDCWr = DDAR_Ser0UDCWr, /* Ser. port 0 UDC Write */ + DMA_Ser0UDCRd = DDAR_Ser0UDCRd, /* Ser. port 0 UDC Read */ + DMA_Ser1UARTWr = DDAR_Ser1UARTWr, /* Ser. port 1 UART Write */ + DMA_Ser1UARTRd = DDAR_Ser1UARTRd, /* Ser. port 1 UART Read */ + DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr, /* Ser. port 1 SDLC Write */ + DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd, /* Ser. port 1 SDLC Read */ + DMA_Ser2UARTWr = DDAR_Ser2UARTWr, /* Ser. port 2 UART Write */ + DMA_Ser2UARTRd = DDAR_Ser2UARTRd, /* Ser. port 2 UART Read */ + DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr, /* Ser. port 2 HSSP Write */ + DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd, /* Ser. port 2 HSSP Read */ + DMA_Ser3UARTWr = DDAR_Ser3UARTWr, /* Ser. port 3 UART Write */ + DMA_Ser3UARTRd = DDAR_Ser3UARTRd, /* Ser. port 3 UART Read */ + DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr, /* Ser. port 4 MCP 0 Write (audio) */ + DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd, /* Ser. port 4 MCP 0 Read (audio) */ + DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr, /* Ser. port 4 MCP 1 Write */ + DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd, /* Ser. port 4 MCP 1 Read */ + DMA_Ser4SSPWr = DDAR_Ser4SSPWr, /* Ser. port 4 SSP Write (16 bits) */ + DMA_Ser4SSPRd = DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */ +} dma_device_t; + + +typedef void (*dma_callback_t)( void *buf_id, int size ); + + +/* SA1100 DMA API */ +extern int sa1100_request_dma( dmach_t *channel, const char *device_id ); +extern int sa1100_dma_set_callback( dmach_t channel, dma_callback_t cb ); +extern int sa1100_dma_set_device( dmach_t channel, dma_device_t device ); +extern int sa1100_dma_set_spin( dmach_t channel, dma_addr_t addr, int size ); +extern int sa1100_dma_queue_buffer( dmach_t channel, void *buf_id, + dma_addr_t data, int size ); +extern int sa1100_dma_get_current( dmach_t channel, void **buf_id, dma_addr_t *addr ); +extern int sa1100_dma_stop( dmach_t channel ); +extern int sa1100_dma_resume( dmach_t channel ); +extern int sa1100_dma_flush_all( dmach_t channel ); +extern void sa1100_free_dma( dmach_t channel ); + +/* Sa1111 DMA interface (all but registration uses the above) */ +extern int sa1111_sac_request_dma( dmach_t *channel, const char *device_id, + unsigned int direction ); +extern int sa1111_check_dma_bug( dma_addr_t addr ); + #endif /* _ASM_ARCH_DMA_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/keyboard.h linux/include/asm-arm/arch-sa1100/keyboard.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/keyboard.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-sa1100/keyboard.h Thu Apr 12 12:20:31 2001 @@ -10,7 +10,9 @@ #include <linux/config.h> -#ifdef CONFIG_SA1100_BRUTUS +// #ifdef CONFIG_SA1100_BRUTUS +/* need fixing... */ +#if 0 extern int Brutus_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); @@ -32,6 +34,113 @@ #define SYSRQ_KEY 0x54 +#elif CONFIG_SA1100_GRAPHICSCLIENT +extern int gc_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); +extern void gc_kbd_leds(unsigned char leds); +extern void gc_kbd_init_hw(void); +extern void gc_kbd_enable_irq(void); +extern void gc_kbd_disable_irq(void); +extern unsigned char gc_kbd_sysrq_xlate[128]; + +#define kbd_setkeycode(x...) (-ENOSYS) +#define kbd_getkeycode(x...) (-ENOSYS) +#define kbd_translate gc_kbd_translate +#define kbd_unexpected_up(x...) (1) +#define kbd_leds gc_kbd_leds +#define kbd_init_hw gc_kbd_init_hw +#define kbd_enable_irq gc_kbd_enable_irq +#define kbd_disable_irq gc_kbd_disable_irq +#define kbd_sysrq_xlate gc_kbd_sysrq_xlate + +#elif defined(CONFIG_SA1111) /*@@@@@*/ + +#define KEYBOARD_IRQ TPRXINT +#define DISABLE_KBD_DURING_INTERRUPTS 0 + +/* redefine some macros */ +#ifdef KBD_DATA_REG +#undef KBD_DATA_REG +#endif +#ifdef KBD_STATUS_REG +#undef KBD_STATUS_REG +#endif +#ifdef KBD_CNTL_REG +#undef KBD_CNTL_REG +#endif +#define KBD_DATA_REG KBDDATA +#define KBD_STATUS_REG KBDSTAT +#define KBD_CNTL_REG KBDCR + +extern int sa1111_setkeycode(unsigned int scancode, unsigned int keycode); +extern int sa1111_getkeycode(unsigned int scancode); +extern int sa1111_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char sa1111_unexpected_up(unsigned char keycode); +extern void sa1111_leds(unsigned char leds); +extern void sa1111_init_hw(void); +extern unsigned char sa1111_sysrq_xlate[128]; + +#define kbd_setkeycode sa1111_setkeycode +#define kbd_getkeycode sa1111_getkeycode +#define kbd_translate sa1111_translate +#define kbd_unexpected_up sa1111_unexpected_up +#define kbd_leds sa1111_leds +#define kbd_init_hw sa1111_init_hw +#define kbd_sysrq_xlate sa1111_sysrq_xlate +#define kbd_disable_irq(x...) do{;}while(0) +#define kbd_enable_irq(x...) do{;}while(0) + +#define SYSRQ_KEY 0x54 + +/* resource allocation */ +#define kbd_request_region() +#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ + "keyboard", NULL) + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() (*KBDDATA & 0x00ff) +#define kbd_read_status() (*KBDSTAT & 0x01ff) +#define kbd_write_output(val) (*KBDDATA = (val)) +#define kbd_write_command(val) (*KBDCR = (val)) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do {;} while(0) + +/* bit definitions for some registers */ +#define KBD_CR_ENA (1<<3) + +#define KBD_STAT_RXB (1<<4) +#define KBD_STAT_RXF (1<<5) +#define KBD_STAT_TXB (1<<6) +#define KBD_STAT_TXE (1<<7) +#define KBD_STAT_STP (1<<8) + +/* + * Machine specific bits for the PS/2 driver + */ + +#define AUX_IRQ MSRXINT + +#define aux_request_irq(hand, dev_id) \ + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) +#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) + +/* How to access the mouse macros on this platform. */ +#define mse_read_input() (*MSEDATA & 0x00ff) +#define mse_read_status() (*MSESTAT & 0x01ff) +#define mse_write_output(val) (*MSEDATA = (val)) +#define mse_write_command(val) (*MSECR = (val)) + +/* bit definitions for some registers */ +#define MSE_CR_ENA (1<<3) + +#define MSE_STAT_RXB (1<<4) +#define MSE_STAT_RXF (1<<5) +#define MSE_STAT_TXB (1<<6) +#define MSE_STAT_TXE (1<<7) +#define MSE_STAT_STP (1<<8) + + #else /* dummy i.e. no real keyboard */ @@ -39,11 +148,18 @@ #define kbd_getkeycode(x...) (-ENOSYS) #define kbd_translate(x...) (0) #define kbd_unexpected_up(x...) (1) -#define kbd_leds(x...) do { } while (0) -#define kbd_init_hw(x...) do { } while (0) -#define kbd_enable_irq(x...) do { } while (0) -#define kbd_disable_irq(x...) do { } while (0) +#define kbd_leds(x...) do {;} while (0) +#define kbd_init_hw(x...) do {;} while (0) +#define kbd_enable_irq(x...) do {;} while (0) +#define kbd_disable_irq(x...) do {;} while (0) + +#endif + +/* needed if MAGIC_SYSRQ is enabled for serial console */ +#ifndef SYSRQ_KEY +#define SYSRQ_KEY -1 +#define kbd_sysrq_xlate ((unsigned char *)NULL) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/mmzone.h linux/include/asm-arm/arch-sa1100/mmzone.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/mmzone.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-sa1100/mmzone.h Thu Apr 12 12:20:31 2001 @@ -21,21 +21,7 @@ * node 3: 0xd8000000 - 0xdfffffff */ - -/* - * Currently defined in arch/arm/mm/mm-sa1100.c - */ -extern pg_data_t sa1100_node_data[]; - -/* - * Return a pointer to the node data for node n. - */ -#define NODE_DATA(nid) (&sa1100_node_data[nid]) - -/* - * NODE_MEM_MAP gives the kaddr for the mem_map of the node. - */ -#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) +#define NR_NODES 4 /* * Given a kernel address, find the home node of the underlying memory. @@ -71,7 +57,7 @@ */ #define VALID_PAGE(page) \ ({ unsigned int node = KVADDR_TO_NID(page); \ - ( (node < 4) && \ + ( (node < NR_NODES) && \ ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size) ); \ }) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/pcmcia.h linux/include/asm-arm/arch-sa1100/pcmcia.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/pcmcia.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-sa1100/pcmcia.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,70 @@ +/* + * linux/include/asm/arch/pcmcia.h + * + * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu> + * + * This file contains definitions for the low-level SA-1100 kernel PCMCIA + * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. + */ + +#ifndef _ASM_ARCH_PCMCIA +#define _ASM_ARCH_PCMCIA + + +/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only + * has support for two. This shows up in lots of hardwired ways, such + * as the fact that MECR only has enough bits to configure two sockets. + * Since it's so entrenched in the hardware, limiting the software + * in this way doesn't seem too terrible. + */ +#define SA1100_PCMCIA_MAX_SOCK (2) + + +#ifndef __ASSEMBLY__ + +struct pcmcia_init { + void (*handler)(int irq, void *dev, struct pt_regs *regs); +}; + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +struct pcmcia_state_array { + unsigned int size; + struct pcmcia_state *state; +}; + +struct pcmcia_configure { + unsigned sock: 8, + vcc: 8, + vpp: 8, + output: 1, + speaker: 1, + reset: 1; +}; + +struct pcmcia_irq_info { + unsigned int sock; + unsigned int irq; +}; + +struct pcmcia_low_level { + int (*init)(struct pcmcia_init *); + int (*shutdown)(void); + int (*socket_state)(struct pcmcia_state_array *); + int (*get_irq_info)(struct pcmcia_irq_info *); + int (*configure_socket)(const struct pcmcia_configure *); +}; + +extern struct pcmcia_low_level *pcmcia_low_level; + +#endif /* __ASSEMBLY__ */ + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/serial.h linux/include/asm-arm/arch-sa1100/serial.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/serial.h Thu Jan 13 13:30:31 2000 +++ linux/include/asm-arm/arch-sa1100/serial.h Thu Apr 12 12:20:31 2001 @@ -22,11 +22,18 @@ #define RS_TABLE_SIZE 4 -#define STD_SERIAL_PORT_DEFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x3F8, IRQ_GPIO3, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, IRQ_GPIO3, STD_COM_FLAGS }, /* ttyS1 */ \ - { 0, BASE_BAUD, 0x3E8, IRQ_GPIO3, STD_COM_FLAGS }, /* ttyS2 */ \ - { 0, BASE_BAUD, 0x2E8, IRQ_GPIO3, STD_COM4_FLAGS } /* ttyS3 */ +/* + * Rather empty table... + * Hardwired serial ports should be defined here. + * PCMCIA will fill it dynamically. + */ +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS }, \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS }, \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS }, \ + { 0, BASE_BAUD, 0, 0, STD_COM_FLAGS } + +#define EXTRA_SERIAL_PORT_DEFNS diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h --- v2.4.3/linux/include/asm-arm/arch-sa1100/system.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-sa1100/system.h Thu Apr 12 12:20:31 2001 @@ -7,7 +7,7 @@ static inline void arch_idle(void) { - while (!current->need_resched && !hlt_counter) + if (!hlt_counter) cpu_do_idle(0); } diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/dma.h linux/include/asm-arm/arch-shark/dma.h --- v2.4.3/linux/include/asm-arm/arch-shark/dma.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/dma.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/dma.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/hardware.h linux/include/asm-arm/arch-shark/hardware.h --- v2.4.3/linux/include/asm-arm/arch-shark/hardware.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-shark/hardware.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/hardware.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa110/hardware.h @@ -40,14 +40,16 @@ /* defines for the Framebuffer */ #define FB_START 0x06000000 -/* Registers for Framebuffer */ -/*#define FBREG_START 0x06800000*/ - #define UNCACHEABLE_ADDR 0xdf010000 #define SEQUOIA_LED_GREEN (1<<6) #define SEQUOIA_LED_AMBER (1<<5) #define SEQUOIA_LED_BACK (1<<7) + +#define pcibios_assign_all_busses() 1 + +#define PCIBIOS_MIN_IO 0x6000 +#define PCIBIOS_MIN_MEM 0x50000000 #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/ide.h linux/include/asm-arm/arch-shark/ide.h --- v2.4.3/linux/include/asm-arm/arch-shark/ide.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/arch-shark/ide.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/ide.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa285/ide.h diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/io.h linux/include/asm-arm/arch-shark/io.h --- v2.4.3/linux/include/asm-arm/arch-shark/io.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-shark/io.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/io.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa110/io.h diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/irq.h linux/include/asm-arm/arch-shark/irq.h --- v2.4.3/linux/include/asm-arm/arch-shark/irq.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/irq.h Thu Apr 12 12:20:31 2001 @@ -1,13 +1,14 @@ /* * linux/include/asm-arm/arch-shark/irq.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from linux/arch/ppc/kernel/i8259.c and: * include/asm-arm/arch-ebsa110/irq.h * Copyright (C) 1996-1998 Russell King */ +#include <asm/io.h> #define fixup_irq(x) (x) /* diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/irqs.h linux/include/asm-arm/arch-shark/irqs.h --- v2.4.3/linux/include/asm-arm/arch-shark/irqs.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/irqs.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/irqs.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ #define NR_IRQS 16 diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/keyboard.h linux/include/asm-arm/arch-shark/keyboard.h --- v2.4.3/linux/include/asm-arm/arch-shark/keyboard.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-shark/keyboard.h Thu Apr 12 12:20:31 2001 @@ -1,6 +1,6 @@ /* * linux/include/asm-arm/arch-shark/keyboard.h - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * Derived from linux/include/asm-arm/arch-ebsa285/keyboard.h * (C) 1998 Russell King diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/memory.h linux/include/asm-arm/arch-shark/memory.h --- v2.4.3/linux/include/asm-arm/arch-shark/memory.h Mon Nov 27 17:07:59 2000 +++ linux/include/asm-arm/arch-shark/memory.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/memory.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * derived from: * linux/include/asm-arm/arch-ebsa110/memory.h diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/param.h linux/include/asm-arm/arch-shark/param.h --- v2.4.3/linux/include/asm-arm/arch-shark/param.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/param.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/param.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ /* This must be a power of 2 because the RTC diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/system.h linux/include/asm-arm/arch-shark/system.h --- v2.4.3/linux/include/asm-arm/arch-shark/system.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-shark/system.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/system.h * - * Copyright (c) 1996-1998 Russell King. + * by Alexander Schulz <aschulz@netwinder.org> */ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/time.h linux/include/asm-arm/arch-shark/time.h --- v2.4.3/linux/include/asm-arm/arch-shark/time.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-shark/time.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-shark/time.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> * * Uses the real time clock because you can't run * the timer with level triggered interrupts and diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/timex.h linux/include/asm-arm/arch-shark/timex.h --- v2.4.3/linux/include/asm-arm/arch-shark/timex.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/timex.h Thu Apr 12 12:20:31 2001 @@ -1,5 +1,5 @@ /* * linux/include/asm-arm/arch-shark/timex.h * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander Schulz <aschulz@netwinder.org> */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-shark/uncompress.h linux/include/asm-arm/arch-shark/uncompress.h --- v2.4.3/linux/include/asm-arm/arch-shark/uncompress.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/uncompress.h Thu Apr 12 12:20:31 2001 @@ -1,31 +1,57 @@ /* - * linux/include/asm-arm/arch-ebsa110/uncompress.h + * linux/include/asm-arm/arch-shark/uncompress.h + * by Alexander Schulz <aschulz@netwinder.org> * + * derived from: + * linux/include/asm-arm/arch-ebsa285/uncompress.h * Copyright (C) 1996,1997,1998 Russell King */ +#define SERIAL_BASE ((volatile unsigned char *)0x400003f8) + +static __inline__ void putc(char c) +{ + int t; + + SERIAL_BASE[0] = c; + t=0x10000; + while (t--); +} + /* * This does not append a newline */ static void puts(const char *s) { - __asm__ __volatile__(" - ldrb %0, [%2], #1 - teq %0, #0 - beq 3f -1: strb %0, [%3] -2: ldrb %1, [%3, #0x14] - and %1, %1, #0x60 - teq %1, #0x60 - bne 2b - teq %0, #'\n' - moveq %0, #'\r' - beq 1b - ldrb %0, [%2], #1 - teq %0, #0 - bne 1b -3: " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc"); + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +#ifdef DEBUG +static void putn(unsigned long z) +{ + int i; + char x; + + putc('0'); + putc('x'); + for (i=0;i<8;i++) { + x='0'+((z>>((7-i)*4))&0xf); + if (x>'9') x=x-'0'+'A'-10; + putc(x); + } +} + +static void putr() +{ + putc('\n'); + putc('\r'); } +#endif /* * nothing to do diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/arch-tbox/time.h linux/include/asm-arm/arch-tbox/time.h --- v2.4.3/linux/include/asm-arm/arch-tbox/time.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-tbox/time.h Thu Apr 12 12:20:31 2001 @@ -8,6 +8,13 @@ * our soft copy. */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #include <asm/io.h> #include <asm/hardware.h> diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/byteorder.h linux/include/asm-arm/byteorder.h --- v2.4.3/linux/include/asm-arm/byteorder.h Fri Oct 27 10:55:01 2000 +++ linux/include/asm-arm/byteorder.h Thu Apr 12 12:20:31 2001 @@ -1,6 +1,21 @@ +/* + * linux/include/asm-arm/byteorder.h + * + * ARM Endian-ness. In little endian mode, the data bus is connected such + * that byte accesses appear as: + * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31 + * and word accesses (data or instruction) appear as: + * d0...d31 + * + * When in big endian mode, byte accesses appear as: + * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7 + * and word accesses (data or instruction) appear as: + * d0...d31 + */ #ifndef __ASM_ARM_BYTEORDER_H #define __ASM_ARM_BYTEORDER_H + #include <asm/types.h> #if !defined(__STRICT_ANSI__) || defined(__KERNEL__) @@ -8,7 +23,11 @@ # define __SWAB_64_THRU_32__ #endif +#ifdef __ARMEB__ +#include <linux/byteorder/big_endian.h> +#else #include <linux/byteorder/little_endian.h> +#endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/elf.h linux/include/asm-arm/elf.h --- v2.4.3/linux/include/asm-arm/elf.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/elf.h Thu Apr 12 12:20:31 2001 @@ -30,7 +30,7 @@ */ #define ELF_CLASS ELFCLASS32 #ifdef __ARMEB__ -#define ELF_DATA ELFDATA2LSB; +#define ELF_DATA ELFDATA2MSB; #else #define ELF_DATA ELFDATA2LSB; #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/clps7111.h linux/include/asm-arm/hardware/clps7111.h --- v2.4.3/linux/include/asm-arm/hardware/clps7111.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/clps7111.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,181 @@ +/* + * linux/include/asm-arm/hardware/clps7111.h + * + * This file contains the hardware definitions of the CLPS7111 internal + * registers. + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + */ +#ifndef __ASM_HARDWARE_CLPS7111_H +#define __ASM_HARDWARE_CLPS7111_H + +#define CLPS7111_PHYS_BASE (0x80000000) + +#ifndef __ASSEMBLY__ +#define clps_readb(off) __raw_readb(CLPS7111_BASE + (off)) +#define clps_readl(off) __raw_readl(CLPS7111_BASE + (off)) +#define clps_writeb(val,off) __raw_writeb(val, CLPS7111_BASE + (off)) +#define clps_writel(val,off) __raw_writel(val, CLPS7111_BASE + (off)) +#endif + +#define PADR (0x0000) +#define PBDR (0x0001) +#define PDDR (0x0003) +#define PADDR (0x0040) +#define PBDDR (0x0041) +#define PDDDR (0x0043) +#define PEDR (0x0080) +#define PEDDR (0x00c0) +#define SYSCON1 (0x0100) +#define SYSFLG1 (0x0140) +#define MEMCFG1 (0x0180) +#define MEMCFG2 (0x01c0) +#define DRFPR (0x0200) +#define INTSR1 (0x0240) +#define INTMR1 (0x0280) +#define LCDCON (0x02c0) +#define TC2D (0x0340) +#define RTCDR (0x0380) +#define RTCMR (0x03c0) +#define PMPCON (0x0400) +#define CODR (0x0440) +#define UARTDR1 (0x0480) +#define UBRLCR1 (0x04c0) +#define SYNCIO (0x0500) +#define PALLSW (0x0540) +#define PALMSW (0x0580) +#define STFCLR (0x05c0) +#define BLEOI (0x0600) +#define MCEOI (0x0640) +#define TEOI (0x0680) +#define TC1EOI (0x06c0) +#define TC2EOI (0x0700) +#define RTCEOI (0x0740) +#define UMSEOI (0x0780) +#define COEOI (0x07c0) +#define HALT (0x0800) +#define STDBY (0x0840) + +#define FBADDR (0x1000) +#define SYSCON2 (0x1100) +#define SYSFLG2 (0x1140) +#define INTSR2 (0x1240) +#define INTMR2 (0x1280) +#define UARTDR2 (0x1480) +#define UBRLCR2 (0x14c0) +#define SS2DR (0x1500) +#define SRXEOF (0x1600) +#define SS2POP (0x16c0) +#define KBDEOI (0x1700) + +/* common bits: SYSCON1 / SYSCON2 */ +#define SYSCON_UARTEN (1 << 8) + +#define SYSCON1_KBDSCAN(x) ((x) & 15) +#define SYSCON1_KBDSCANMASK (15) +#define SYSCON1_TC1M (1 << 4) +#define SYSCON1_TC1S (1 << 5) +#define SYSCON1_TC2M (1 << 6) +#define SYSCON1_TC2S (1 << 7) +#define SYSCON1_UART1EN SYSCON_UARTEN +#define SYSCON1_BZTOG (1 << 9) +#define SYSCON1_BZMOD (1 << 10) +#define SYSCON1_DBGEN (1 << 11) +#define SYSCON1_LCDEN (1 << 12) +#define SYSCON1_CDENTX (1 << 13) +#define SYSCON1_CDENRX (1 << 14) +#define SYSCON1_SIREN (1 << 15) +#define SYSCON1_ADCKSEL(x) (((x) & 3) << 16) +#define SYSCON1_ADCKSEL_MASK (3 << 16) +#define SYSCON1_EXCKEN (1 << 18) +#define SYSCON1_WAKEDIS (1 << 19) +#define SYSCON1_IRTXM (1 << 20) + +/* common bits: SYSFLG1 / SYSFLG2 */ +#define SYSFLG_UBUSY (1 << 11) +#define SYSFLG_URXFE (1 << 22) +#define SYSFLG_UTXFF (1 << 23) + +#define SYSFLG1_MCDR (1 << 0) +#define SYSFLG1_DCDET (1 << 1) +#define SYSFLG1_WUDR (1 << 2) +#define SYSFLG1_WUON (1 << 3) +#define SYSFLG1_CTS (1 << 8) +#define SYSFLG1_DSR (1 << 9) +#define SYSFLG1_DCD (1 << 10) +#define SYSFLG1_UBUSY SYSFLG_UBUSY +#define SYSFLG1_NBFLG (1 << 12) +#define SYSFLG1_RSTFLG (1 << 13) +#define SYSFLG1_PFFLG (1 << 14) +#define SYSFLG1_CLDFLG (1 << 15) +#define SYSFLG1_URXFE SYSFLG_URXFE +#define SYSFLG1_UTXFF SYSFLG_UTXFF +#define SYSFLG1_CRXFE (1 << 24) +#define SYSFLG1_CTXFF (1 << 25) +#define SYSFLG1_SSIBUSY (1 << 26) +#define SYSFLG1_ID (1 << 29) + +#define SYSFLG2_SSRXOF (1 << 0) +#define SYSFLG2_RESVAL (1 << 1) +#define SYSFLG2_RESFRM (1 << 2) +#define SYSFLG2_SS2RXFE (1 << 3) +#define SYSFLG2_SS2TXFF (1 << 4) +#define SYSFLG2_SS2TXUF (1 << 5) +#define SYSFLG2_CKMODE (1 << 6) +#define SYSFLG2_UBUSY SYSFLG_UBUSY +#define SYSFLG2_URXFE SYSFLG_URXFE +#define SYSFLG2_UTXFF SYSFLG_UTXFF + +#define LCDCON_GSEN (1 << 30) +#define LCDCON_GSMD (1 << 31) + +#define SYSCON2_SERSEL (1 << 0) +#define SYSCON2_KBD6 (1 << 1) +#define SYSCON2_DRAMZ (1 << 2) +#define SYSCON2_KBWEN (1 << 3) +#define SYSCON2_SS2TXEN (1 << 4) +#define SYSCON2_PCCARD1 (1 << 5) +#define SYSCON2_PCCARD2 (1 << 6) +#define SYSCON2_SS2RXEN (1 << 7) +#define SYSCON2_UART2EN SYSCON_UARTEN +#define SYSCON2_SS2MAEN (1 << 9) +#define SYSCON2_OSTB (1 << 12) +#define SYSCON2_CLKENSL (1 << 13) +#define SYSCON2_BUZFREQ (1 << 14) + +/* common bits: UARTDR1 / UARTDR2 */ +#define UARTDR_FRMERR (1 << 8) +#define UARTDR_PARERR (1 << 9) +#define UARTDR_OVERR (1 << 10) + +/* common bits: UBRLCR1 / UBRLCR2 */ +#define UBRLCR_BAUD_MASK ((1 << 12) - 1) +#define UBRLCR_BREAK (1 << 12) +#define UBRLCR_PRTEN (1 << 13) +#define UBRLCR_EVENPRT (1 << 14) +#define UBRLCR_XSTOP (1 << 15) +#define UBRLCR_FIFOEN (1 << 16) +#define UBRLCR_WRDLEN5 (0 << 17) +#define UBRLCR_WRDLEN6 (1 << 17) +#define UBRLCR_WRDLEN7 (2 << 17) +#define UBRLCR_WRDLEN8 (3 << 17) +#define UBRLCR_WRDLEN_MASK (3 << 17) + +#define SYNCIO_SMCKEN (1 << 13) +#define SYNCIO_TXFRMEN (1 << 14) + +#endif /* __ASM_HARDWARE_CLPS7111_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/ep7212.h linux/include/asm-arm/hardware/ep7212.h --- v2.4.3/linux/include/asm-arm/hardware/ep7212.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/ep7212.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,84 @@ +/* + * linux/include/asm-arm/hardware/ep7212.h + * + * This file contains the hardware definitions of the EP7212 internal + * registers. + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + */ +#ifndef __ASM_HARDWARE_EP7212_H +#define __ASM_HARDWARE_EP7212_H + +/* + * define EP7212_BASE to be the base address of the region + * you want to access. + */ + +#define EP7212_PHYS_BASE (0x80000000) + +#ifndef __ASSEMBLY__ +#define ep_readl(off) __raw_readl(EP7212_BASE + (off)) +#define ep_writel(val,off) __raw_writel(val, EP7212_BASE + (off)) +#endif + +/* + * These registers are specific to the EP7212 only + */ +#define DAIR 0x2000 +#define DAIR0 0x2040 +#define DAIDR1 0x2080 +#define DAIDR2 0x20c0 +#define DAISR 0x2100 +#define SYSCON3 0x2200 +#define INTSR3 0x2240 +#define INTMR3 0x2280 +#define LEDFLSH 0x22c0 + +#define DAIR_DAIEN (1 << 16) +#define DAIR_ECS (1 << 17) +#define DAIR_LCTM (1 << 19) +#define DAIR_LCRM (1 << 20) +#define DAIR_RCTM (1 << 21) +#define DAIR_RCRM (1 << 22) +#define DAIR_LBM (1 << 23) + +#define DAIDR2_FIFOEN (1 << 15) +#define DAIDR2_FIFOLEFT (0x0d << 16) +#define DAIDR2_FIFORIGHT (0x11 << 16) + +#define DAISR_RCTS (1 << 0) +#define DAISR_RCRS (1 << 1) +#define DAISR_LCTS (1 << 2) +#define DAISR_LCRS (1 << 3) +#define DAISR_RCTU (1 << 4) +#define DAISR_RCRO (1 << 5) +#define DAISR_LCTU (1 << 6) +#define DAISR_LCRO (1 << 7) +#define DAISR_RCNF (1 << 8) +#define DAISR_RCNE (1 << 9) +#define DAISR_LCNF (1 << 10) +#define DAISR_LCNE (1 << 11) +#define DAISR_FIFO (1 << 12) + +#define SYSCON3_ADCCON (1 << 0) +#define SYSCON3_DAISEL (1 << 3) +#define SYSCON3_ADCCKNSEN (1 << 4) +#define SYSCON3_FASTWAKE (1 << 8) +#define SYSCON3_DAIEN (1 << 9) + + +#endif /* __ASM_HARDWARE_EP7212_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/ioc.h linux/include/asm-arm/hardware/ioc.h --- v2.4.3/linux/include/asm-arm/hardware/ioc.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/hardware/ioc.h Thu Apr 12 12:20:31 2001 @@ -10,58 +10,63 @@ * Use these macros to read/write the IOC. All it does is perform the actual * read/write. */ - -#ifndef IOC_CONTROL +#ifndef __ASMARM_HARDWARE_IOC_H +#define __ASMARM_HARDWARE_IOC_H #ifndef __ASSEMBLY__ -#define __IOC(offset) (IOC_BASE + (offset >> 2)) -#else -#define __IOC(offset) offset + +/* + * We use __raw_base variants here so that we give the compiler the + * chance to keep IOC_BASE in a register. + */ +#define ioc_readb(off) __raw_base_readb(IOC_BASE, (off)) +#define ioc_writeb(val,off) __raw_base_writeb(val, IOC_BASE, (off)) + #endif -#define IOC_CONTROL __IOC(0x00) -#define IOC_KARTTX __IOC(0x04) -#define IOC_KARTRX __IOC(0x04) - -#define IOC_IRQSTATA __IOC(0x10) -#define IOC_IRQREQA __IOC(0x14) -#define IOC_IRQCLRA __IOC(0x14) -#define IOC_IRQMASKA __IOC(0x18) - -#define IOC_IRQSTATB __IOC(0x20) -#define IOC_IRQREQB __IOC(0x24) -#define IOC_IRQMASKB __IOC(0x28) - -#define IOC_FIQSTAT __IOC(0x30) -#define IOC_FIQREQ __IOC(0x34) -#define IOC_FIQMASK __IOC(0x38) - -#define IOC_T0CNTL __IOC(0x40) -#define IOC_T0LTCHL __IOC(0x40) -#define IOC_T0CNTH __IOC(0x44) -#define IOC_T0LTCHH __IOC(0x44) -#define IOC_T0GO __IOC(0x48) -#define IOC_T0LATCH __IOC(0x4c) - -#define IOC_T1CNTL __IOC(0x50) -#define IOC_T1LTCHL __IOC(0x50) -#define IOC_T1CNTH __IOC(0x54) -#define IOC_T1LTCHH __IOC(0x54) -#define IOC_T1GO __IOC(0x58) -#define IOC_T1LATCH __IOC(0x5c) - -#define IOC_T2CNTL __IOC(0x60) -#define IOC_T2LTCHL __IOC(0x60) -#define IOC_T2CNTH __IOC(0x64) -#define IOC_T2LTCHH __IOC(0x64) -#define IOC_T2GO __IOC(0x68) -#define IOC_T2LATCH __IOC(0x6c) - -#define IOC_T3CNTL __IOC(0x70) -#define IOC_T3LTCHL __IOC(0x70) -#define IOC_T3CNTH __IOC(0x74) -#define IOC_T3LTCHH __IOC(0x74) -#define IOC_T3GO __IOC(0x78) -#define IOC_T3LATCH __IOC(0x7c) +#define IOC_CONTROL (0x00) +#define IOC_KARTTX (0x04) +#define IOC_KARTRX (0x04) + +#define IOC_IRQSTATA (0x10) +#define IOC_IRQREQA (0x14) +#define IOC_IRQCLRA (0x14) +#define IOC_IRQMASKA (0x18) + +#define IOC_IRQSTATB (0x20) +#define IOC_IRQREQB (0x24) +#define IOC_IRQMASKB (0x28) + +#define IOC_FIQSTAT (0x30) +#define IOC_FIQREQ (0x34) +#define IOC_FIQMASK (0x38) + +#define IOC_T0CNTL (0x40) +#define IOC_T0LTCHL (0x40) +#define IOC_T0CNTH (0x44) +#define IOC_T0LTCHH (0x44) +#define IOC_T0GO (0x48) +#define IOC_T0LATCH (0x4c) + +#define IOC_T1CNTL (0x50) +#define IOC_T1LTCHL (0x50) +#define IOC_T1CNTH (0x54) +#define IOC_T1LTCHH (0x54) +#define IOC_T1GO (0x58) +#define IOC_T1LATCH (0x5c) + +#define IOC_T2CNTL (0x60) +#define IOC_T2LTCHL (0x60) +#define IOC_T2CNTH (0x64) +#define IOC_T2LTCHH (0x64) +#define IOC_T2GO (0x68) +#define IOC_T2LATCH (0x6c) + +#define IOC_T3CNTL (0x70) +#define IOC_T3LTCHL (0x70) +#define IOC_T3CNTH (0x74) +#define IOC_T3LTCHH (0x74) +#define IOC_T3GO (0x78) +#define IOC_T3LATCH (0x7c) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/hardware/iomd.h linux/include/asm-arm/hardware/iomd.h --- v2.4.3/linux/include/asm-arm/hardware/iomd.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/hardware/iomd.h Thu Apr 12 12:20:31 2001 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/iomd.h + * linux/include/asm-arm/hardware/iomd.h * * Copyright (C) 1999 Russell King * @@ -10,111 +10,121 @@ * This file contains information out the IOMD ASIC used in the * Acorn RiscPC and subsequently integrated into the CLPS7500 chips. */ +#ifndef __ASMARM_HARDWARE_IOMD_H +#define __ASMARM_HARDWARE_IOMD_H + #include <linux/config.h> #ifndef __ASSEMBLY__ -#define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2)) -#else -#define __IOMD(offset) offset + +/* + * We use __raw_base variants here so that we give the compiler the + * chance to keep IOC_BASE in a register. + */ +#define iomd_readb(off) __raw_base_readb(IOMD_BASE, (off)) +#define iomd_readl(off) __raw_base_readl(IOMD_BASE, (off)) +#define iomd_writeb(val,off) __raw_base_writeb(val, IOMD_BASE, (off)) +#define iomd_writel(val,off) __raw_base_writel(val, IOMD_BASE, (off)) + #endif -#define IOMD_CONTROL __IOMD(0x000) -#define IOMD_KARTTX __IOMD(0x004) -#define IOMD_KARTRX __IOMD(0x004) -#define IOMD_KCTRL __IOMD(0x008) +#define IOMD_CONTROL (0x000) +#define IOMD_KARTTX (0x004) +#define IOMD_KARTRX (0x004) +#define IOMD_KCTRL (0x008) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_IOLINES __IOMD(0x00C) +#define IOMD_IOLINES (0x00C) #endif -#define IOMD_IRQSTATA __IOMD(0x010) -#define IOMD_IRQREQA __IOMD(0x014) -#define IOMD_IRQCLRA __IOMD(0x014) -#define IOMD_IRQMASKA __IOMD(0x018) +#define IOMD_IRQSTATA (0x010) +#define IOMD_IRQREQA (0x014) +#define IOMD_IRQCLRA (0x014) +#define IOMD_IRQMASKA (0x018) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_SUSMODE __IOMD(0x01C) +#define IOMD_SUSMODE (0x01C) #endif -#define IOMD_IRQSTATB __IOMD(0x020) -#define IOMD_IRQREQB __IOMD(0x024) -#define IOMD_IRQMASKB __IOMD(0x028) +#define IOMD_IRQSTATB (0x020) +#define IOMD_IRQREQB (0x024) +#define IOMD_IRQMASKB (0x028) -#define IOMD_FIQSTAT __IOMD(0x030) -#define IOMD_FIQREQ __IOMD(0x034) -#define IOMD_FIQMASK __IOMD(0x038) +#define IOMD_FIQSTAT (0x030) +#define IOMD_FIQREQ (0x034) +#define IOMD_FIQMASK (0x038) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_CLKCTL __IOMD(0x03C) +#define IOMD_CLKCTL (0x03C) #endif -#define IOMD_T0CNTL __IOMD(0x040) -#define IOMD_T0LTCHL __IOMD(0x040) -#define IOMD_T0CNTH __IOMD(0x044) -#define IOMD_T0LTCHH __IOMD(0x044) -#define IOMD_T0GO __IOMD(0x048) -#define IOMD_T0LATCH __IOMD(0x04c) +#define IOMD_T0CNTL (0x040) +#define IOMD_T0LTCHL (0x040) +#define IOMD_T0CNTH (0x044) +#define IOMD_T0LTCHH (0x044) +#define IOMD_T0GO (0x048) +#define IOMD_T0LATCH (0x04c) -#define IOMD_T1CNTL __IOMD(0x050) -#define IOMD_T1LTCHL __IOMD(0x050) -#define IOMD_T1CNTH __IOMD(0x054) -#define IOMD_T1LTCHH __IOMD(0x054) -#define IOMD_T1GO __IOMD(0x058) -#define IOMD_T1LATCH __IOMD(0x05c) +#define IOMD_T1CNTL (0x050) +#define IOMD_T1LTCHL (0x050) +#define IOMD_T1CNTH (0x054) +#define IOMD_T1LTCHH (0x054) +#define IOMD_T1GO (0x058) +#define IOMD_T1LATCH (0x05c) #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_IRQSTATC __IOMD(0x060) -#define IOMD_IRQREQC __IOMD(0x064) -#define IOMD_IRQMASKC __IOMD(0x068) +#define IOMD_IRQSTATC (0x060) +#define IOMD_IRQREQC (0x064) +#define IOMD_IRQMASKC (0x068) -#define IOMD_VIDMUX __IOMD(0x06c) +#define IOMD_VIDMUX (0x06c) -#define IOMD_IRQSTATD __IOMD(0x070) -#define IOMD_IRQREQD __IOMD(0x074) -#define IOMD_IRQMASKD __IOMD(0x078) +#define IOMD_IRQSTATD (0x070) +#define IOMD_IRQREQD (0x074) +#define IOMD_IRQMASKD (0x078) #endif -#define IOMD_ROMCR0 __IOMD(0x080) -#define IOMD_ROMCR1 __IOMD(0x084) +#define IOMD_ROMCR0 (0x080) +#define IOMD_ROMCR1 (0x084) #ifdef CONFIG_ARCH_RPC -#define IOMD_DRAMCR __IOMD(0x088) +#define IOMD_DRAMCR (0x088) #endif -#define IOMD_REFCR __IOMD(0x08C) +#define IOMD_REFCR (0x08C) -#define IOMD_FSIZE __IOMD(0x090) -#define IOMD_ID0 __IOMD(0x094) -#define IOMD_ID1 __IOMD(0x098) -#define IOMD_VERSION __IOMD(0x09C) +#define IOMD_FSIZE (0x090) +#define IOMD_ID0 (0x094) +#define IOMD_ID1 (0x098) +#define IOMD_VERSION (0x09C) #ifdef CONFIG_ARCH_RPC -#define IOMD_MOUSEX __IOMD(0x0A0) -#define IOMD_MOUSEY __IOMD(0x0A4) +#define IOMD_MOUSEX (0x0A0) +#define IOMD_MOUSEY (0x0A4) #endif #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_MSEDAT __IOMD(0x0A8) -#define IOMD_MSECTL __IOMD(0x0Ac) +#define IOMD_MSEDAT (0x0A8) +#define IOMD_MSECTL (0x0Ac) #endif #ifdef CONFIG_ARCH_RPC -#define IOMD_DMATCR __IOMD(0x0C0) +#define IOMD_DMATCR (0x0C0) #endif -#define IOMD_IOTCR __IOMD(0x0C4) -#define IOMD_ECTCR __IOMD(0x0C8) +#define IOMD_IOTCR (0x0C4) +#define IOMD_ECTCR (0x0C8) #ifdef CONFIG_ARCH_RPC -#define IOMD_DMAEXT __IOMD(0x0CC) +#define IOMD_DMAEXT (0x0CC) #endif #ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_ASTCR __IOMD(0x0CC) -#define IOMD_DRAMCR __IOMD(0x0D0) -#define IOMD_SELFREF __IOMD(0x0D4) -#define IOMD_ATODICR __IOMD(0x0E0) -#define IOMD_ATODSR __IOMD(0x0E4) -#define IOMD_ATODCC __IOMD(0x0E8) -#define IOMD_ATODCNT1 __IOMD(0x0EC) -#define IOMD_ATODCNT2 __IOMD(0x0F0) -#define IOMD_ATODCNT3 __IOMD(0x0F4) -#define IOMD_ATODCNT4 __IOMD(0x0F8) +#define IOMD_ASTCR (0x0CC) +#define IOMD_DRAMCR (0x0D0) +#define IOMD_SELFREF (0x0D4) +#define IOMD_ATODICR (0x0E0) +#define IOMD_ATODSR (0x0E4) +#define IOMD_ATODCC (0x0E8) +#define IOMD_ATODCNT1 (0x0EC) +#define IOMD_ATODCNT2 (0x0F0) +#define IOMD_ATODCNT3 (0x0F4) +#define IOMD_ATODCNT4 (0x0F8) #endif #ifdef CONFIG_ARCH_RPC @@ -123,63 +133,63 @@ #define DMA_EXT_IO2 4 #define DMA_EXT_IO3 8 -#define IOMD_IO0CURA __IOMD(0x100) -#define IOMD_IO0ENDA __IOMD(0x104) -#define IOMD_IO0CURB __IOMD(0x108) -#define IOMD_IO0ENDB __IOMD(0x10C) -#define IOMD_IO0CR __IOMD(0x110) -#define IOMD_IO0ST __IOMD(0x114) - -#define IOMD_IO1CURA __IOMD(0x120) -#define IOMD_IO1ENDA __IOMD(0x124) -#define IOMD_IO1CURB __IOMD(0x128) -#define IOMD_IO1ENDB __IOMD(0x12C) -#define IOMD_IO1CR __IOMD(0x130) -#define IOMD_IO1ST __IOMD(0x134) - -#define IOMD_IO2CURA __IOMD(0x140) -#define IOMD_IO2ENDA __IOMD(0x144) -#define IOMD_IO2CURB __IOMD(0x148) -#define IOMD_IO2ENDB __IOMD(0x14C) -#define IOMD_IO2CR __IOMD(0x150) -#define IOMD_IO2ST __IOMD(0x154) - -#define IOMD_IO3CURA __IOMD(0x160) -#define IOMD_IO3ENDA __IOMD(0x164) -#define IOMD_IO3CURB __IOMD(0x168) -#define IOMD_IO3ENDB __IOMD(0x16C) -#define IOMD_IO3CR __IOMD(0x170) -#define IOMD_IO3ST __IOMD(0x174) -#endif - -#define IOMD_SD0CURA __IOMD(0x180) -#define IOMD_SD0ENDA __IOMD(0x184) -#define IOMD_SD0CURB __IOMD(0x188) -#define IOMD_SD0ENDB __IOMD(0x18C) -#define IOMD_SD0CR __IOMD(0x190) -#define IOMD_SD0ST __IOMD(0x194) - -#ifdef CONFIG_ARCH_RPC -#define IOMD_SD1CURA __IOMD(0x1A0) -#define IOMD_SD1ENDA __IOMD(0x1A4) -#define IOMD_SD1CURB __IOMD(0x1A8) -#define IOMD_SD1ENDB __IOMD(0x1AC) -#define IOMD_SD1CR __IOMD(0x1B0) -#define IOMD_SD1ST __IOMD(0x1B4) -#endif - -#define IOMD_CURSCUR __IOMD(0x1C0) -#define IOMD_CURSINIT __IOMD(0x1C4) - -#define IOMD_VIDCUR __IOMD(0x1D0) -#define IOMD_VIDEND __IOMD(0x1D4) -#define IOMD_VIDSTART __IOMD(0x1D8) -#define IOMD_VIDINIT __IOMD(0x1DC) -#define IOMD_VIDCR __IOMD(0x1E0) - -#define IOMD_DMASTAT __IOMD(0x1F0) -#define IOMD_DMAREQ __IOMD(0x1F4) -#define IOMD_DMAMASK __IOMD(0x1F8) +#define IOMD_IO0CURA (0x100) +#define IOMD_IO0ENDA (0x104) +#define IOMD_IO0CURB (0x108) +#define IOMD_IO0ENDB (0x10C) +#define IOMD_IO0CR (0x110) +#define IOMD_IO0ST (0x114) + +#define IOMD_IO1CURA (0x120) +#define IOMD_IO1ENDA (0x124) +#define IOMD_IO1CURB (0x128) +#define IOMD_IO1ENDB (0x12C) +#define IOMD_IO1CR (0x130) +#define IOMD_IO1ST (0x134) + +#define IOMD_IO2CURA (0x140) +#define IOMD_IO2ENDA (0x144) +#define IOMD_IO2CURB (0x148) +#define IOMD_IO2ENDB (0x14C) +#define IOMD_IO2CR (0x150) +#define IOMD_IO2ST (0x154) + +#define IOMD_IO3CURA (0x160) +#define IOMD_IO3ENDA (0x164) +#define IOMD_IO3CURB (0x168) +#define IOMD_IO3ENDB (0x16C) +#define IOMD_IO3CR (0x170) +#define IOMD_IO3ST (0x174) +#endif + +#define IOMD_SD0CURA (0x180) +#define IOMD_SD0ENDA (0x184) +#define IOMD_SD0CURB (0x188) +#define IOMD_SD0ENDB (0x18C) +#define IOMD_SD0CR (0x190) +#define IOMD_SD0ST (0x194) + +#ifdef CONFIG_ARCH_RPC +#define IOMD_SD1CURA (0x1A0) +#define IOMD_SD1ENDA (0x1A4) +#define IOMD_SD1CURB (0x1A8) +#define IOMD_SD1ENDB (0x1AC) +#define IOMD_SD1CR (0x1B0) +#define IOMD_SD1ST (0x1B4) +#endif + +#define IOMD_CURSCUR (0x1C0) +#define IOMD_CURSINIT (0x1C4) + +#define IOMD_VIDCUR (0x1D0) +#define IOMD_VIDEND (0x1D4) +#define IOMD_VIDSTART (0x1D8) +#define IOMD_VIDINIT (0x1DC) +#define IOMD_VIDCR (0x1E0) + +#define IOMD_DMASTAT (0x1F0) +#define IOMD_DMAREQ (0x1F4) +#define IOMD_DMAMASK (0x1F8) #define DMA_END_S (1 << 31) #define DMA_END_L (1 << 30) @@ -192,39 +202,6 @@ #define DMA_ST_INT 2 #define DMA_ST_AB 1 -#ifndef IOC_CONTROL -/* - * IOC compatability - */ -#define IOC_CONTROL IOMD_CONTROL -#define IOC_IRQSTATA IOMD_IRQSTATA -#define IOC_IRQREQA IOMD_IRQREQA -#define IOC_IRQCLRA IOMD_IRQCLRA -#define IOC_IRQMASKA IOMD_IRQMASKA - -#define IOC_IRQSTATB IOMD_IRQSTATB -#define IOC_IRQREQB IOMD_IRQREQB -#define IOC_IRQMASKB IOMD_IRQMASKB - -#define IOC_FIQSTAT IOMD_FIQSTAT -#define IOC_FIQREQ IOMD_FIQREQ -#define IOC_FIQMASK IOMD_FIQMASK - -#define IOC_T0CNTL IOMD_T0CNTL -#define IOC_T0LTCHL IOMD_T0LTCHL -#define IOC_T0CNTH IOMD_T0CNTH -#define IOC_T0LTCHH IOMD_T0LTCHH -#define IOC_T0GO IOMD_T0GO -#define IOC_T0LATCH IOMD_T0LATCH - -#define IOC_T1CNTL IOMD_T1CNTL -#define IOC_T1LTCHL IOMD_T1LTCHL -#define IOC_T1CNTH IOMD_T1CNTH -#define IOC_T1LTCHH IOMD_T1LTCHH -#define IOC_T1GO IOMD_T1GO -#define IOC_T1LATCH IOMD_T1LATCH -#endif - /* * DMA (MEMC) compatability */ @@ -247,3 +224,4 @@ } while (0) #endif +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/io.h linux/include/asm-arm/io.h --- v2.4.3/linux/include/asm-arm/io.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/io.h Thu Apr 12 12:20:31 2001 @@ -104,11 +104,13 @@ _ret = __ioremap(iomem_to_phys(_off),_size,0); \ _ret; \ }) + +#define __arch_iounmap __iounmap #endif #define ioremap(off,sz) __arch_ioremap((off),(sz),0) #define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) -#define iounmap(_addr) __iounmap(_addr) +#define iounmap(_addr) __arch_iounmap(_addr) /* * DMA-consistent mapping functions. These allocate/free a region of @@ -188,7 +190,7 @@ return retval; } -#else /* __mem_pci */ +#elif !defined(readb) #define readb(addr) (__readwrite_bug("readb"),0) #define readw(addr) (__readwrite_bug("readw"),0) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/mmzone.h linux/include/asm-arm/mmzone.h --- v2.4.3/linux/include/asm-arm/mmzone.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/mmzone.h Thu Apr 12 12:20:31 2001 @@ -10,6 +10,21 @@ #ifndef __ASM_MMZONE_H #define __ASM_MMZONE_H +/* + * Currently defined in arch/arm/mm/discontig.c + */ +extern pg_data_t discontig_node_data[]; + +/* + * Return a pointer to the node data for node n. + */ +#define NODE_DATA(nid) (&discontig_node_data[nid]) + +/* + * NODE_MEM_MAP gives the kaddr for the mem_map of the node. + */ +#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) + #include <asm/arch/mmzone.h> #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/pgalloc.h linux/include/asm-arm/pgalloc.h --- v2.4.3/linux/include/asm-arm/pgalloc.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/pgalloc.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/pgalloc.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000-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 @@ -25,6 +25,11 @@ #define flush_tlb_pgtables(mm,start,end) do { } while (0) /* + * Processor specific parts... + */ +#include <asm/proc/pgalloc.h> + +/* * Page table cache stuff */ #ifndef CONFIG_NO_PGT_CACHE @@ -68,20 +73,13 @@ pgtable_cache_size++; } -/* We don't use pmd cache, so this is a dummy routine */ -#define get_pmd_fast() ((pmd_t *)0) - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ -} - -extern __inline__ pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; if((ret = pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)__pte_next(ret); - ret[0] = ret[1]; + ret[0] = 0; clean_dcache_entry(ret); pgtable_cache_size--; } @@ -97,119 +95,47 @@ #else /* CONFIG_NO_PGT_CACHE */ -#define pgd_quicklist ((unsigned long *)0) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist ((unsigned long *)0) +#define pgd_quicklist ((unsigned long *)0) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist ((unsigned long *)0) -#define get_pgd_fast() ((pgd_t *)0) -#define get_pmd_fast() ((pmd_t *)0) -#define get_pte_fast() ((pte_t *)0) - -#define free_pgd_fast(pgd) free_pgd_slow(pgd) -#define free_pmd_fast(pmd) free_pmd_slow(pmd) -#define free_pte_fast(pte) free_pte_slow(pte) +#define get_pgd_fast() ((pgd_t *)0) +#define pte_alloc_one_fast(mm,addr) ((pte_t *)0) -#endif /* CONFIG_NO_PGT_CACHE */ +#define free_pgd_fast(pgd) free_pgd_slow(pgd) +#define free_pte_fast(pte) pte_free_slow(pte) -extern pgd_t *get_pgd_slow(void); -extern void free_pgd_slow(pgd_t *pgd); +#endif /* CONFIG_NO_PGT_CACHE */ -#define free_pmd_slow(pmd) do { } while (0) +#define pte_free(pte) free_pte_fast(pte) -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long addr_preadjusted); -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long addr_preadjusted); -extern void free_pte_slow(pte_t *pte); /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Since we have only two-level page tables, these are trivial */ -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) +#define pmd_alloc_one_fast(mm,addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(pmd) do { } while (0) +#define pmd_free_fast(pmd) do { } while (0) +#define pmd_free(pmd) do { } while (0) +#define pgd_populate(mm,pmd,pte) BUG() -#ifndef pte_alloc_kernel -extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_kernel_slow(pmd, address); - set_pmd(pmd, mk_kernel_pmd(page)); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} -#endif - -extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - set_pmd(pmd, mk_user_pmd(page)); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -#define pmd_free_kernel pmd_free -#define pmd_free(pmd) do { } while (0) - -#define pmd_alloc_kernel pmd_alloc -extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -#define pgd_free(pgd) free_pgd_fast(pgd) +extern pgd_t *get_pgd_slow(struct mm_struct *mm); +extern void free_pgd_slow(pgd_t *pgd); -extern __inline__ pgd_t *pgd_alloc(void) +extern __inline__ pgd_t *pgd_alloc(struct mm_struct *mm) { pgd_t *pgd; pgd = get_pgd_fast(); if (!pgd) - pgd = get_pgd_slow(); + pgd = get_pgd_slow(mm); return pgd; } -extern int do_check_pgt_cache(int, int); +#define pgd_free(pgd) free_pgd_fast(pgd) -extern __inline__ void set_pgdir(unsigned long address, pgd_t entry) -{ - struct task_struct * p; - - read_lock(&tasklist_lock); - for_each_task(p) { - if (!p->mm) - continue; - *pgd_offset(p->mm,address) = entry; - } - read_unlock(&tasklist_lock); - -#ifndef CONFIG_NO_PGT_CACHE - { - pgd_t *pgd; - for (pgd = (pgd_t *)pgd_quicklist; pgd; - pgd = (pgd_t *)__pgd_next(pgd)) - pgd[address >> PGDIR_SHIFT] = entry; - } -#endif -} +extern int do_check_pgt_cache(int, int); #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h --- v2.4.3/linux/include/asm-arm/pgtable.h Tue Mar 6 19:44:35 2001 +++ linux/include/asm-arm/pgtable.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/pgtable.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000-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 @@ -75,12 +75,6 @@ extern struct page *empty_zero_page; #define ZERO_PAGE(vaddr) (empty_zero_page) -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd(pmd_t *pmd); -extern void __handle_bad_pmd_kernel(pmd_t *pmd); - #define pte_none(pte) (!pte_val(pte)) #define pte_clear(ptep) set_pte((ptep), __pte(0)) @@ -98,6 +92,7 @@ #endif #define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_present(pmd) (pmd_val(pmd)) #define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0)) /* @@ -163,8 +158,6 @@ } extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; - -#define update_mmu_cache(vma,address,pte) do { } while (0) /* Encode and decode a swap entry. * diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h --- v2.4.3/linux/include/asm-arm/proc-armo/cache.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/proc-armo/cache.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armo/cache.h * - * Copyright (C) 1999-2000 Russell King + * Copyright (C) 1999-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 @@ -37,8 +37,9 @@ * - flush_tlb_range(mm, start, end) flushes a range of pages */ #define flush_tlb_all() memc_update_all() -#define flush_tlb_mm(mm) do { } while (0) -#define flush_tlb_range(mm, start, end) do { (void)(start); (void)(end); } while (0) +#define flush_tlb_mm(mm) memc_update_mm(mm) +#define flush_tlb_range(mm,start,end) \ + do { memc_update_mm(mm); (void)(start); (void)(end); } while (0) #define flush_tlb_page(vma, vmaddr) do { } while (0) /* @@ -57,7 +58,7 @@ processor._set_pgd(current->active_mm->pgd); } -extern __inline__ void memc_update_mm(struct mm_struct *mm) +static inline void memc_update_mm(struct mm_struct *mm) { cpu_memc_update_all(mm->pgd); @@ -66,19 +67,26 @@ } extern __inline__ void -memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr) +memc_clear(struct mm_struct *mm, struct page *page) { - cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr); + cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0); if (mm == current->active_mm) processor._set_pgd(mm->pgd); } -extern __inline__ void -memc_clear(struct mm_struct *mm, struct page *page) +static inline void +memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr) { - cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0); + cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr); if (mm == current->active_mm) processor._set_pgd(mm->pgd); +} + +static inline void +update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + struct mm_struct *mm = vma->vm_mm; + memc_update_addr(mm, pte, addr); } diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/pgalloc.h linux/include/asm-arm/proc-armo/pgalloc.h --- v2.4.3/linux/include/asm-arm/proc-armo/pgalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/proc-armo/pgalloc.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,47 @@ +/* + * linux/include/asm-arm/proc-armo/pgalloc.h + * + * Copyright (C) 2001 Russell King + * + * Page table allocation/freeing primitives for 26-bit ARM processors. + */ + +/* unfortunately, this includes linux/mm.h and the rest of the universe. */ +#include <linux/slab.h> + +extern kmem_cache_t *pte_cache; + +/* + * Allocate one PTE table. + * + * Note that we keep the processor copy of the PTE entries separate + * from the Linux copy. The processor copies are offset by -PTRS_PER_PTE + * words from the Linux copy. + */ +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + return kmem_cache_alloc(pte_cache, GFP_KERNEL); +} + +/* + * Free one PTE table. + */ +static inline void pte_free_slow(pte_t *pte) +{ + if (pte) + kmem_cache_free(pte_cache, pte); +} + +/* + * Populate the pmdp entry with a pointer to the pte. This pmd is part + * of the mm address space. + * + * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we + * need to set stuff up correctly for it. + */ +#define pmd_populate(mm,pmdp,pte) \ + do { \ + set_pmd(pmdp, __mk_pmd(pte, _PAGE_TABLE)); \ + } while (0) + + diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h --- v2.4.3/linux/include/asm-arm/proc-armo/pgtable.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/proc-armo/pgtable.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armo/pgtable.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (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 @@ -33,7 +33,7 @@ #define pmd_bad(pmd) ((pmd_val(pmd) & 0xfc000002)) #define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd)) -extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) +static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) { unsigned long pte_ptr = (unsigned long)ptep; pmd_t pmd; @@ -43,11 +43,7 @@ return pmd; } -/* these are aliases for the above function */ -#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_TABLE) -#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_TABLE) - -extern __inline__ unsigned long pmd_page(pmd_t pmd) +static inline unsigned long pmd_page(pmd_t pmd) { return __phys_to_virt(pmd_val(pmd) & ~_PAGE_TABLE); } @@ -81,7 +77,6 @@ #define pte_dirty(pte) (!(pte_val(pte) & _PAGE_CLEAN)) #define pte_young(pte) (!(pte_val(pte) & _PAGE_OLD)) -extern inline pte_t pte_nocache(pte_t pte) { return pte; } extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_READONLY; return pte; } extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) |= _PAGE_NOT_USER; return pte; } extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) |= _PAGE_NOT_USER; return pte; } diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h --- v2.4.3/linux/include/asm-arm/proc-armo/ptrace.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/proc-armo/ptrace.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armo/ptrace.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-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 @@ -14,6 +14,10 @@ #define FIQ26_MODE 0x01 #define IRQ26_MODE 0x02 #define SVC26_MODE 0x03 +#define USR_MODE USR26_MODE +#define FIQ_MODE FIQ26_MODE +#define IRQ_MODE IRQ26_MODE +#define SVC_MODE SVC26_MODE #define MODE_MASK 0x03 #define F_BIT (1 << 26) #define I_BIT (1 << 27) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h --- v2.4.3/linux/include/asm-arm/proc-armv/cache.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/proc-armv/cache.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armv/cache.h * - * Copyright (C) 1999-2000 Russell King + * Copyright (C) 1999-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 @@ -154,3 +154,9 @@ cpu_tlb_invalidate_page((_page), \ ((_vma)->vm_flags & VM_EXEC)); \ } while (0) + +/* + * 32-bit ARM Processors don't have any MMU cache + */ +#define update_mmu_cache(vma,address,pte) do { } while (0) + diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/pgalloc.h linux/include/asm-arm/proc-armv/pgalloc.h --- v2.4.3/linux/include/asm-arm/proc-armv/pgalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/proc-armv/pgalloc.h Thu Apr 12 12:20:31 2001 @@ -0,0 +1,58 @@ +/* + * linux/include/asm-arm/proc-armv/pgalloc.h + * + * Copyright (C) 2001 Russell King + * + * Page table allocation/freeing primitives for 32-bit ARM processors. + */ + +/* unfortunately, this includes linux/mm.h and the rest of the universe. */ +#include <linux/slab.h> + +extern kmem_cache_t *pte_cache; + +/* + * Allocate one PTE table. + * + * Note that we keep the processor copy of the PTE entries separate + * from the Linux copy. The processor copies are offset by -PTRS_PER_PTE + * words from the Linux copy. + */ +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + pte = kmem_cache_alloc(pte_cache, GFP_KERNEL); + if (pte) + pte += PTRS_PER_PTE; + return pte; +} + +/* + * Free one PTE table. + */ +static inline void pte_free_slow(pte_t *pte) +{ + if (pte) { + pte -= PTRS_PER_PTE; + kmem_cache_free(pte_cache, pte); + } +} + +/* + * Populate the pmdp entry with a pointer to the pte. This pmd is part + * of the mm address space. + * + * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we + * need to set stuff up correctly for it. + */ +#define pmd_populate(mm,pmdp,pte) \ + do { \ + unsigned long __prot; \ + if (mm == &init_mm) \ + __prot = _PAGE_KERNEL_TABLE; \ + else \ + __prot = _PAGE_USER_TABLE; \ + set_pmd(pmdp, __mk_pmd(pte, __prot)); \ + } while (0) + diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h --- v2.4.3/linux/include/asm-arm/proc-armv/pgtable.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/proc-armv/pgtable.h Thu Apr 12 12:20:31 2001 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/proc-armv/pgtable.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (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 @@ -48,7 +48,7 @@ #define pmd_bad(pmd) (pmd_val(pmd) & 2) #define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd) -extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) +static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) { unsigned long pte_ptr = (unsigned long)ptep; pmd_t pmd; @@ -64,11 +64,7 @@ return pmd; } -/* these are aliases for the above function */ -#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_USER_TABLE) -#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_KERNEL_TABLE) - -extern __inline__ unsigned long pmd_page(pmd_t pmd) +static inline unsigned long pmd_page(pmd_t pmd) { unsigned long ptr; @@ -161,7 +157,6 @@ PTE_BIT_FUNC(mkdirty, |= L_PTE_DIRTY); PTE_BIT_FUNC(mkold, &= ~L_PTE_YOUNG); PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG); -PTE_BIT_FUNC(nocache, &= ~L_PTE_CACHEABLE); /* * Mark the prot value as uncacheable and unbufferable. diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h --- v2.4.3/linux/include/asm-arm/proc-armv/uaccess.h Tue Mar 6 19:44:35 2001 +++ linux/include/asm-arm/proc-armv/uaccess.h Thu Apr 12 12:20:31 2001 @@ -91,7 +91,7 @@ " .align 3\n" \ " .long 1b, 3b\n" \ " .previous" \ - : "=r" (err), "=r" (x) \ + : "=r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT), "0" (err)) #define __get_user_asm_half(x,addr,err) \ @@ -117,7 +117,7 @@ " .align 3\n" \ " .long 1b, 3b\n" \ " .previous" \ - : "=r" (err), "=r" (x) \ + : "=r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT), "0" (err)) extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n); diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h --- v2.4.3/linux/include/asm-arm/processor.h Sat Dec 30 09:35:40 2000 +++ linux/include/asm-arm/processor.h Thu Apr 12 12:20:31 2001 @@ -38,6 +38,7 @@ #define EISA_bus 0 #define MCA_bus 0 +#define MCA_bus__is_a_macro #include <asm/atomic.h> #include <asm/ptrace.h> diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/procinfo.h linux/include/asm-arm/procinfo.h --- v2.4.3/linux/include/asm-arm/procinfo.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/procinfo.h Thu Apr 12 12:20:31 2001 @@ -46,10 +46,13 @@ #endif /* __ASSEMBLY__ */ -#define HWCAP_SWP 1 -#define HWCAP_HALF 2 -#define HWCAP_THUMB 4 -#define HWCAP_26BIT 8 /* Play it safe */ +#define HWCAP_SWP 1 +#define HWCAP_HALF 2 +#define HWCAP_THUMB 4 +#define HWCAP_26BIT 8 /* Play it safe */ +#define HWCAP_FAST_MULT 16 +#define HWCAP_FPA 32 +#define HWCAP_VFP 64 +#define HWCAP_EDSP 128 #endif - diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h --- v2.4.3/linux/include/asm-arm/semaphore.h Sun Feb 13 10:47:01 2000 +++ linux/include/asm-arm/semaphore.h Tue Apr 17 17:19:30 2001 @@ -7,6 +7,7 @@ #include <linux/linkage.h> #include <linux/spinlock.h> #include <linux/wait.h> +#include <linux/rwsem.h> #include <asm/atomic.h> #include <asm/proc/locks.h> @@ -122,135 +123,6 @@ #endif __up_op(sem, __up_wakeup); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned char write_bias_granted; - volatile unsigned char read_bias_granted; - volatile unsigned char pad1; - volatile unsigned char pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -extern struct rw_semaphore *__down_read_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *__down_write_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem); - -extern inline void down_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - __down_op_read(sem, __down_read_failed); -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - __down_op_write(sem, __down_write_failed); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -extern inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_op_read(sem, __rwsem_wake); -} - -extern inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_op_write(sem, __rwsem_wake); } #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/setup.h linux/include/asm-arm/setup.h --- v2.4.3/linux/include/asm-arm/setup.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/setup.h Thu Apr 12 12:20:31 2001 @@ -207,7 +207,7 @@ /* * Memory map description */ -#define NR_BANKS 4 +#define NR_BANKS 8 struct meminfo { int nr_banks; diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h --- v2.4.3/linux/include/asm-arm/unistd.h Tue Mar 6 19:44:35 2001 +++ linux/include/asm-arm/unistd.h Thu Apr 12 12:20:31 2001 @@ -224,6 +224,10 @@ #define __NR_setfsuid32 (__NR_SYSCALL_BASE+215) #define __NR_setfsgid32 (__NR_SYSCALL_BASE+216) #define __NR_getdents64 (__NR_SYSCALL_BASE+217) +#define __NR_pivot_root (__NR_SYSCALL_BASE+218) +#define __NR_mincore (__NR_SYSCALL_BASE+219) +#define __NR_madvise (__NR_SYSCALL_BASE+220) +#define __NR_fcntl64 (__NR_SYSCALL_BASE+221) #define __sys2(x) #x #define __sys1(x) __sys2(x) diff -u --recursive --new-file v2.4.3/linux/include/asm-arm/xor.h linux/include/asm-arm/xor.h --- v2.4.3/linux/include/asm-arm/xor.h Tue Mar 6 19:44:35 2001 +++ linux/include/asm-arm/xor.h Thu Apr 12 12:20:31 2001 @@ -8,7 +8,289 @@ * published by the Free Software Foundation. */ +/* + * linux/include/asm-arm/xor.h + * + * 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. + */ + +/* + * linux/include/asm-arm/xor.h + * + * 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 <asm-generic/xor.h> + +#define __XOR(a1, a2) a1 ^= a2 + +#define GET_BLOCK_2(dst) \ + __asm__("ldmia %0, {%1, %2}" \ + : "=r" (dst), "=r" (a1), "=r" (a2) \ + : "0" (dst)) + +#define GET_BLOCK_4(dst) \ + __asm__("ldmia %0, {%1, %2, %3, %4}" \ + : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ + : "0" (dst)) + +#define XOR_BLOCK_2(src) \ + __asm__("ldmia %0!, {%1, %2}" \ + : "=r" (src), "=r" (b1), "=r" (b2) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); + +#define XOR_BLOCK_4(src) \ + __asm__("ldmia %0!, {%1, %2, %3, %4}" \ + : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) + +#define PUT_BLOCK_2(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2)) + +#define PUT_BLOCK_4(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) + +static void +xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + XOR_BLOCK_4(p3); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static void +xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + XOR_BLOCK_2(p5); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static struct xor_block_template xor_block_arm4regs = { + name: "arm4regs", + do_2: xor_arm4regs_2, + do_3: xor_arm4regs_3, + do_4: xor_arm4regs_4, + do_5: xor_arm4regs_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_arm4regs); \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + } while (0) + +#define __XOR(a1, a2) a1 ^= a2 + +#define GET_BLOCK_2(dst) \ + __asm__("ldmia %0, {%1, %2}" \ + : "=r" (dst), "=r" (a1), "=r" (a2) \ + : "0" (dst)) + +#define GET_BLOCK_4(dst) \ + __asm__("ldmia %0, {%1, %2, %3, %4}" \ + : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ + : "0" (dst)) + +#define XOR_BLOCK_2(src) \ + __asm__("ldmia %0!, {%1, %2}" \ + : "=r" (src), "=r" (b1), "=r" (b2) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); + +#define XOR_BLOCK_4(src) \ + __asm__("ldmia %0!, {%1, %2, %3, %4}" \ + : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) + +#define PUT_BLOCK_2(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2)) + +#define PUT_BLOCK_4(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) + +static void +xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + XOR_BLOCK_4(p3); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static void +xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + XOR_BLOCK_2(p5); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static struct xor_block_template xor_block_arm4regs = { + name: "arm4regs", + do_2: xor_arm4regs_2, + do_3: xor_arm4regs_3, + do_4: xor_arm4regs_4, + do_5: xor_arm4regs_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_arm4regs); \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + } while (0) #define __XOR(a1, a2) a1 ^= a2 diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/bitops.h linux/include/asm-cris/bitops.h --- v2.4.3/linux/include/asm-cris/bitops.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/bitops.h Fri Apr 6 10:51:19 2001 @@ -1,9 +1,12 @@ -/* $Id: bitops.h,v 1.3 2000/10/17 14:56:27 bjornw Exp $ */ +/* $Id: bitops.h,v 1.4 2001/02/28 04:26:11 hp Exp $ */ /* all of these should probably be rewritten in assembler for speed. */ #ifndef _CRIS_BITOPS_H #define _CRIS_BITOPS_H +/* Currently this is unsuitable for consumption outside the kernel. */ +#ifdef __KERNEL__ + #include <asm/system.h> /* @@ -163,8 +166,6 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) - -#ifdef __KERNEL__ #define ext2_set_bit test_and_set_bit #define ext2_clear_bit test_and_clear_bit diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/delay.h linux/include/asm-cris/delay.h --- v2.4.3/linux/include/asm-cris/delay.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/delay.h Fri Apr 6 10:51:19 2001 @@ -1,4 +1,4 @@ -/* $Id: delay.h,v 1.2 2000/08/08 16:36:41 bjornw Exp $ */ +/* $Id: delay.h,v 1.3 2001/02/23 13:47:33 bjornw Exp $ */ #ifndef _CRIS_DELAY_H #define _CRIS_DELAY_H diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/eshlibld.h linux/include/asm-cris/eshlibld.h --- v2.4.3/linux/include/asm-cris/eshlibld.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/eshlibld.h Fri Apr 6 10:51:19 2001 @@ -12,7 +12,7 @@ *! (C) Copyright 1998, 1999 Axis Communications AB, LUND, SWEDEN *! *!**************************************************************************/ -/* $Id: eshlibld.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ +/* $Id: eshlibld.h,v 1.2 2001/02/23 13:47:33 bjornw Exp $ */ #ifndef _cris_relocate_h #define _cris_relocate_h diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h --- v2.4.3/linux/include/asm-cris/etraxgpio.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-cris/etraxgpio.h Fri Apr 6 10:51:19 2001 @@ -0,0 +1,32 @@ +#ifndef _ASM_ETRAXGPIO_H +#define _ASM_ETRAXGPIO_H + +/* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ + +#define ETRAXGPIO_IOCTYPE 43 + +/* supported ioctl _IOC_NR's */ + +#define IO_READBITS 0x1 /* read and return current port bits */ +#define IO_SETBITS 0x2 /* set the bits marked by 1 in the argument */ +#define IO_CLRBITS 0x3 /* clear the bits marked by 1 in the argument */ + +/* the alarm is waited for by select() */ + +#define IO_HIGHALARM 0x4 /* set alarm on high for bits marked by 1 */ +#define IO_LOWALARM 0x5 /* set alarm on low for bits marked by 1 */ +#define IO_CLRALARM 0x6 /* clear alarm for bits marked by 1 */ + +/* LED ioctl */ +#define IO_LEDACTIVE_SET 0x7 /* set active led + * 0=off, 1=green, 2=red, 3=yellow */ + +/* GPIO direction ioctl's */ +#define IO_READDIR 0x8 /* Read direction 0=input 1=output */ +#define IO_SETINPUT 0x9 /* Set direction 0=unchanged 1=input, + returns current dir */ +#define IO_SETOUTPUT 0xA /* Set direction 0=unchanged 1=output, + returns current dir */ + +#endif + diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/etraxi2c.h linux/include/asm-cris/etraxi2c.h --- v2.4.3/linux/include/asm-cris/etraxi2c.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-cris/etraxi2c.h Fri Apr 6 10:51:19 2001 @@ -0,0 +1,36 @@ +/* $Id: etraxi2c.h,v 1.1 2001/01/18 15:49:57 bjornw Exp $ */ + +#ifndef _LINUX_ETRAXI2C_H +#define _LINUX_ETRAXI2C_H + +/* etraxi2c _IOC_TYPE, bits 8 to 15 in ioctl cmd */ + +#define ETRAXI2C_IOCTYPE 44 + +/* supported ioctl _IOC_NR's */ + +/* in write operations, the argument contains both i2c + * slave, register and value. + */ + +#define I2C_WRITEARG(slave, reg, value) (((slave) << 16) | ((reg) << 8) | (value)) +#define I2C_READARG(slave, reg) (((slave) << 16) | ((reg) << 8)) + +#define I2C_ARGSLAVE(arg) ((arg) >> 16) +#define I2C_ARGREG(arg) (((arg) >> 8) & 0xff) +#define I2C_ARGVALUE(arg) ((arg) & 0xff) + +#define I2C_WRITEREG 0x1 /* write to an i2c register */ +#define I2C_READREG 0x2 /* read from an i2c register */ + +/* +EXAMPLE usage: + + i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); + ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); + + i2c_arg = I2C_READARG(STA013_READ_ADDR, reg); + val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); + +*/ +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/io.h linux/include/asm-cris/io.h --- v2.4.3/linux/include/asm-cris/io.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/io.h Fri Apr 6 10:51:19 2001 @@ -9,9 +9,9 @@ use will be evident. */ #ifdef CONFIG_SVINTO_SIM /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\ +#define SIMCOUT(s,len) asm ("moveq 4,r9\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\ \n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \ - : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory") + : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") #define TRACE_ON() __extension__ \ ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ (255)); _Foofoo; }) @@ -127,6 +127,13 @@ static inline void * phys_to_virt(unsigned long address) { return __va(address); +} + +extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); + +extern inline void * ioremap (unsigned long offset, unsigned long size) +{ + return __ioremap(offset, size, 0); } /* diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h --- v2.4.3/linux/include/asm-cris/irq.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/irq.h Fri Apr 6 10:51:19 2001 @@ -19,7 +19,7 @@ #include <asm/sv_addr_ag.h> -#define NR_IRQS 26 /* TODO: what is this for Etrax100/LX ? */ +#define NR_IRQS 32 extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/processor.h linux/include/asm-cris/processor.h --- v2.4.3/linux/include/asm-cris/processor.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/processor.h Fri Apr 6 10:51:19 2001 @@ -1,7 +1,7 @@ /* * include/asm-cris/processor.h * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen Initial version * @@ -57,9 +57,6 @@ /* saved stack-frame upon syscall entry, points to registers */ #define current_regs() (current->thread.esp0) - -/* this lives in process.c */ -asmlinkage void set_esp0(unsigned long ssp); /* INIT_MMAP is the kernels map of memory, between KSEG_C and KSEG_D */ diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h --- v2.4.3/linux/include/asm-cris/ptrace.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/ptrace.h Fri Apr 6 10:51:19 2001 @@ -23,9 +23,8 @@ #define PT_DCCR 17 #define PT_SRP 18 #define PT_IRP 19 -#define PT_MAX 19 - -#define PT_USP 42 /* special case - USP is not in the pt_regs */ +#define PT_USP 20 /* special case - USP is not in the pt_regs */ +#define PT_MAX 20 /* Frame types */ diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/semaphore.h linux/include/asm-cris/semaphore.h --- v2.4.3/linux/include/asm-cris/semaphore.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/semaphore.h Tue Apr 17 17:19:30 2001 @@ -9,6 +9,7 @@ #include <linux/wait.h> #include <linux/spinlock.h> +#include <linux/rwsem.h> #include <asm/system.h> #include <asm/atomic.h> @@ -155,167 +156,6 @@ if(wakeup) { __up(sem); } -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ - -struct rw_semaphore { - atomic_t count; - /* bit 0 means read bias granted; - bit 1 means write bias granted. */ - unsigned granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -/* The expensive part is outlined. */ -extern void __down_read(struct rw_semaphore *sem, int count); -extern void __down_write(struct rw_semaphore *sem, int count); -extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers); - -extern inline void down_read(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = atomic_dec_return(&sem->count); - if (count < 0) { - __down_read(sem, count); - } - mb(); - -#if WAITQUEUE_DEBUG - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count) { - __down_write(sem, count); - } - mb(); - -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->granted & 3) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant case is when - there was a writer waiting, and we've bumped the count to 0: we must - wake the writer up. */ - -extern inline 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 - - mb(); - if (atomic_inc_return(&sem->count) == 0) - __rwsem_wake(sem, 0); -} - -/* - * Releasing the writer is easy -- just release it and wake up any sleepers. - */ -extern inline void up_write(struct rw_semaphore *sem) -{ - int count; - -#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 - - mb(); - count = atomic_add_return(RW_LOCK_BIAS, &sem->count); - if (count - RW_LOCK_BIAS < 0 && count >= 0) { - /* Only do the wake if we're no longer negative. */ - __rwsem_wake(sem, count); - } } #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/socket.h linux/include/asm-cris/socket.h --- v2.4.3/linux/include/asm-cris/socket.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/socket.h Fri Apr 6 10:51:19 2001 @@ -45,6 +45,8 @@ #define SO_TIMESTAMP 29 #define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_ACCEPTCONN 30 + #if defined(__KERNEL__) /* Socket types. */ #define SOCK_STREAM 1 /* stream (connection) socket */ diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/sv_addr.agh linux/include/asm-cris/sv_addr.agh --- v2.4.3/linux/include/asm-cris/sv_addr.agh Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/sv_addr.agh Fri Apr 6 10:51:19 2001 @@ -1,8 +1,8 @@ /* !* This file was automatically generated by /n/asic/bin/reg_macro_gen -!* from the file `etrax_ng_regs.rd'. +!* from the file `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd'. !* Editing within this file is thus not recommended, -!* make the changes in `etrax_ng_regs.rd' instead. +!* make the changes in `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd' instead. !*/ @@ -103,6 +103,10 @@ #define R_BUS_STATUS__flashw__bw16 0 #define R_DRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008) +#define R_DRAM_TIMING__sdram__BITNR 31 +#define R_DRAM_TIMING__sdram__WIDTH 1 +#define R_DRAM_TIMING__sdram__enable 1 +#define R_DRAM_TIMING__sdram__disable 0 #define R_DRAM_TIMING__ref__BITNR 14 #define R_DRAM_TIMING__ref__WIDTH 2 #define R_DRAM_TIMING__ref__e52us 0 @@ -683,10 +687,6 @@ #define R_GEN_CONFIG__usb1__WIDTH 1 #define R_GEN_CONFIG__usb1__select 1 #define R_GEN_CONFIG__usb1__disable 0 -#define R_GEN_CONFIG__p21__BITNR 28 -#define R_GEN_CONFIG__p21__WIDTH 1 -#define R_GEN_CONFIG__p21__select 1 -#define R_GEN_CONFIG__p21__disable 0 #define R_GEN_CONFIG__g24dir__BITNR 27 #define R_GEN_CONFIG__g24dir__WIDTH 1 #define R_GEN_CONFIG__g24dir__in 0 @@ -2331,6 +2331,10 @@ #define R_NETWORK_GA_1__ga_high__WIDTH 32 #define R_NETWORK_REC_CONFIG (IO_TYPECAST_UDWORD 0xb0000094) +#define R_NETWORK_REC_CONFIG__max_size__BITNR 10 +#define R_NETWORK_REC_CONFIG__max_size__WIDTH 1 +#define R_NETWORK_REC_CONFIG__max_size__size1518 0 +#define R_NETWORK_REC_CONFIG__max_size__size1522 1 #define R_NETWORK_REC_CONFIG__duplex__BITNR 9 #define R_NETWORK_REC_CONFIG__duplex__WIDTH 1 #define R_NETWORK_REC_CONFIG__duplex__full 1 @@ -2535,6 +2539,10 @@ #define R_PAR0_STATUS_DATA__mode__ecp_fwd 5 #define R_PAR0_STATUS_DATA__mode__ecp_rev 6 #define R_PAR0_STATUS_DATA__mode__off 7 +#define R_PAR0_STATUS_DATA__mode__epp_wr1 5 +#define R_PAR0_STATUS_DATA__mode__epp_wr2 6 +#define R_PAR0_STATUS_DATA__mode__epp_wr3 7 +#define R_PAR0_STATUS_DATA__mode__epp_rd 0 #define R_PAR0_STATUS_DATA__perr__BITNR 28 #define R_PAR0_STATUS_DATA__perr__WIDTH 1 #define R_PAR0_STATUS_DATA__perr__active 1 @@ -2555,6 +2563,14 @@ #define R_PAR0_STATUS_DATA__sel__WIDTH 1 #define R_PAR0_STATUS_DATA__sel__active 1 #define R_PAR0_STATUS_DATA__sel__inactive 0 +#define R_PAR0_STATUS_DATA__ext_mode__BITNR 23 +#define R_PAR0_STATUS_DATA__ext_mode__WIDTH 1 +#define R_PAR0_STATUS_DATA__ext_mode__enable 1 +#define R_PAR0_STATUS_DATA__ext_mode__disable 0 +#define R_PAR0_STATUS_DATA__ecp_16__BITNR 22 +#define R_PAR0_STATUS_DATA__ecp_16__WIDTH 1 +#define R_PAR0_STATUS_DATA__ecp_16__active 1 +#define R_PAR0_STATUS_DATA__ecp_16__inactive 0 #define R_PAR0_STATUS_DATA__tr_rdy__BITNR 17 #define R_PAR0_STATUS_DATA__tr_rdy__WIDTH 1 #define R_PAR0_STATUS_DATA__tr_rdy__ready 1 @@ -2570,7 +2586,59 @@ #define R_PAR0_STATUS_DATA__data__BITNR 0 #define R_PAR0_STATUS_DATA__data__WIDTH 8 -#define R_PAR_ECP16_DATA (IO_TYPECAST_RO_UWORD 0xb0000040) +#define R_PAR0_STATUS (IO_TYPECAST_RO_UWORD 0xb0000042) +#define R_PAR0_STATUS__mode__BITNR 13 +#define R_PAR0_STATUS__mode__WIDTH 3 +#define R_PAR0_STATUS__mode__manual 0 +#define R_PAR0_STATUS__mode__centronics 1 +#define R_PAR0_STATUS__mode__fastbyte 2 +#define R_PAR0_STATUS__mode__nibble 3 +#define R_PAR0_STATUS__mode__byte 4 +#define R_PAR0_STATUS__mode__ecp_fwd 5 +#define R_PAR0_STATUS__mode__ecp_rev 6 +#define R_PAR0_STATUS__mode__off 7 +#define R_PAR0_STATUS__mode__epp_wr1 5 +#define R_PAR0_STATUS__mode__epp_wr2 6 +#define R_PAR0_STATUS__mode__epp_wr3 7 +#define R_PAR0_STATUS__mode__epp_rd 0 +#define R_PAR0_STATUS__perr__BITNR 12 +#define R_PAR0_STATUS__perr__WIDTH 1 +#define R_PAR0_STATUS__perr__active 1 +#define R_PAR0_STATUS__perr__inactive 0 +#define R_PAR0_STATUS__ack__BITNR 11 +#define R_PAR0_STATUS__ack__WIDTH 1 +#define R_PAR0_STATUS__ack__active 0 +#define R_PAR0_STATUS__ack__inactive 1 +#define R_PAR0_STATUS__busy__BITNR 10 +#define R_PAR0_STATUS__busy__WIDTH 1 +#define R_PAR0_STATUS__busy__active 1 +#define R_PAR0_STATUS__busy__inactive 0 +#define R_PAR0_STATUS__fault__BITNR 9 +#define R_PAR0_STATUS__fault__WIDTH 1 +#define R_PAR0_STATUS__fault__active 0 +#define R_PAR0_STATUS__fault__inactive 1 +#define R_PAR0_STATUS__sel__BITNR 8 +#define R_PAR0_STATUS__sel__WIDTH 1 +#define R_PAR0_STATUS__sel__active 1 +#define R_PAR0_STATUS__sel__inactive 0 +#define R_PAR0_STATUS__ext_mode__BITNR 7 +#define R_PAR0_STATUS__ext_mode__WIDTH 1 +#define R_PAR0_STATUS__ext_mode__enable 1 +#define R_PAR0_STATUS__ext_mode__disable 0 +#define R_PAR0_STATUS__ecp_16__BITNR 6 +#define R_PAR0_STATUS__ecp_16__WIDTH 1 +#define R_PAR0_STATUS__ecp_16__active 1 +#define R_PAR0_STATUS__ecp_16__inactive 0 +#define R_PAR0_STATUS__tr_rdy__BITNR 1 +#define R_PAR0_STATUS__tr_rdy__WIDTH 1 +#define R_PAR0_STATUS__tr_rdy__ready 1 +#define R_PAR0_STATUS__tr_rdy__busy 0 +#define R_PAR0_STATUS__dav__BITNR 0 +#define R_PAR0_STATUS__dav__WIDTH 1 +#define R_PAR0_STATUS__dav__data 1 +#define R_PAR0_STATUS__dav__nodata 0 + +#define R_PAR_ECP16_DATA (IO_TYPECAST_UWORD 0xb0000040) #define R_PAR_ECP16_DATA__data__BITNR 0 #define R_PAR_ECP16_DATA__data__WIDTH 16 @@ -2669,6 +2737,10 @@ #define R_PAR0_CONFIG__mode__ecp_fwd 5 #define R_PAR0_CONFIG__mode__ecp_rev 6 #define R_PAR0_CONFIG__mode__off 7 +#define R_PAR0_CONFIG__mode__epp_wr1 5 +#define R_PAR0_CONFIG__mode__epp_wr2 6 +#define R_PAR0_CONFIG__mode__epp_wr3 7 +#define R_PAR0_CONFIG__mode__epp_rd 0 #define R_PAR0_DELAY (IO_TYPECAST_UDWORD 0xb0000048) #define R_PAR0_DELAY__fine_hold__BITNR 21 @@ -2731,6 +2803,10 @@ #define R_PAR1_STATUS_DATA__mode__ecp_fwd 5 #define R_PAR1_STATUS_DATA__mode__ecp_rev 6 #define R_PAR1_STATUS_DATA__mode__off 7 +#define R_PAR1_STATUS_DATA__mode__epp_wr1 5 +#define R_PAR1_STATUS_DATA__mode__epp_wr2 6 +#define R_PAR1_STATUS_DATA__mode__epp_wr3 7 +#define R_PAR1_STATUS_DATA__mode__epp_rd 0 #define R_PAR1_STATUS_DATA__perr__BITNR 28 #define R_PAR1_STATUS_DATA__perr__WIDTH 1 #define R_PAR1_STATUS_DATA__perr__active 1 @@ -2751,6 +2827,10 @@ #define R_PAR1_STATUS_DATA__sel__WIDTH 1 #define R_PAR1_STATUS_DATA__sel__active 1 #define R_PAR1_STATUS_DATA__sel__inactive 0 +#define R_PAR1_STATUS_DATA__ext_mode__BITNR 23 +#define R_PAR1_STATUS_DATA__ext_mode__WIDTH 1 +#define R_PAR1_STATUS_DATA__ext_mode__enable 1 +#define R_PAR1_STATUS_DATA__ext_mode__disable 0 #define R_PAR1_STATUS_DATA__tr_rdy__BITNR 17 #define R_PAR1_STATUS_DATA__tr_rdy__WIDTH 1 #define R_PAR1_STATUS_DATA__tr_rdy__ready 1 @@ -2766,6 +2846,54 @@ #define R_PAR1_STATUS_DATA__data__BITNR 0 #define R_PAR1_STATUS_DATA__data__WIDTH 8 +#define R_PAR1_STATUS (IO_TYPECAST_RO_UWORD 0xb0000052) +#define R_PAR1_STATUS__mode__BITNR 13 +#define R_PAR1_STATUS__mode__WIDTH 3 +#define R_PAR1_STATUS__mode__manual 0 +#define R_PAR1_STATUS__mode__centronics 1 +#define R_PAR1_STATUS__mode__fastbyte 2 +#define R_PAR1_STATUS__mode__nibble 3 +#define R_PAR1_STATUS__mode__byte 4 +#define R_PAR1_STATUS__mode__ecp_fwd 5 +#define R_PAR1_STATUS__mode__ecp_rev 6 +#define R_PAR1_STATUS__mode__off 7 +#define R_PAR1_STATUS__mode__epp_wr1 5 +#define R_PAR1_STATUS__mode__epp_wr2 6 +#define R_PAR1_STATUS__mode__epp_wr3 7 +#define R_PAR1_STATUS__mode__epp_rd 0 +#define R_PAR1_STATUS__perr__BITNR 12 +#define R_PAR1_STATUS__perr__WIDTH 1 +#define R_PAR1_STATUS__perr__active 1 +#define R_PAR1_STATUS__perr__inactive 0 +#define R_PAR1_STATUS__ack__BITNR 11 +#define R_PAR1_STATUS__ack__WIDTH 1 +#define R_PAR1_STATUS__ack__active 0 +#define R_PAR1_STATUS__ack__inactive 1 +#define R_PAR1_STATUS__busy__BITNR 10 +#define R_PAR1_STATUS__busy__WIDTH 1 +#define R_PAR1_STATUS__busy__active 1 +#define R_PAR1_STATUS__busy__inactive 0 +#define R_PAR1_STATUS__fault__BITNR 9 +#define R_PAR1_STATUS__fault__WIDTH 1 +#define R_PAR1_STATUS__fault__active 0 +#define R_PAR1_STATUS__fault__inactive 1 +#define R_PAR1_STATUS__sel__BITNR 8 +#define R_PAR1_STATUS__sel__WIDTH 1 +#define R_PAR1_STATUS__sel__active 1 +#define R_PAR1_STATUS__sel__inactive 0 +#define R_PAR1_STATUS__ext_mode__BITNR 7 +#define R_PAR1_STATUS__ext_mode__WIDTH 1 +#define R_PAR1_STATUS__ext_mode__enable 1 +#define R_PAR1_STATUS__ext_mode__disable 0 +#define R_PAR1_STATUS__tr_rdy__BITNR 1 +#define R_PAR1_STATUS__tr_rdy__WIDTH 1 +#define R_PAR1_STATUS__tr_rdy__ready 1 +#define R_PAR1_STATUS__tr_rdy__busy 0 +#define R_PAR1_STATUS__dav__BITNR 0 +#define R_PAR1_STATUS__dav__WIDTH 1 +#define R_PAR1_STATUS__dav__data 1 +#define R_PAR1_STATUS__dav__nodata 0 + #define R_PAR1_CONFIG (IO_TYPECAST_UDWORD 0xb0000054) #define R_PAR1_CONFIG__ioe__BITNR 25 #define R_PAR1_CONFIG__ioe__WIDTH 1 @@ -2857,6 +2985,10 @@ #define R_PAR1_CONFIG__mode__ecp_fwd 5 #define R_PAR1_CONFIG__mode__ecp_rev 6 #define R_PAR1_CONFIG__mode__off 7 +#define R_PAR1_CONFIG__mode__epp_wr1 5 +#define R_PAR1_CONFIG__mode__epp_wr2 6 +#define R_PAR1_CONFIG__mode__epp_wr3 7 +#define R_PAR1_CONFIG__mode__epp_rd 0 #define R_PAR1_DELAY (IO_TYPECAST_UDWORD 0xb0000058) #define R_PAR1_DELAY__fine_hold__BITNR 21 @@ -3437,10 +3569,6 @@ #define R_IRQ_MASK0_RD__ata_irq2__WIDTH 1 #define R_IRQ_MASK0_RD__ata_irq2__active 1 #define R_IRQ_MASK0_RD__ata_irq2__inactive 0 -#define R_IRQ_MASK0_RD__p21_irq2__BITNR 10 -#define R_IRQ_MASK0_RD__p21_irq2__WIDTH 1 -#define R_IRQ_MASK0_RD__p21_irq2__active 1 -#define R_IRQ_MASK0_RD__p21_irq2__inactive 0 #define R_IRQ_MASK0_RD__par0_data__BITNR 9 #define R_IRQ_MASK0_RD__par0_data__WIDTH 1 #define R_IRQ_MASK0_RD__par0_data__active 1 @@ -3449,10 +3577,6 @@ #define R_IRQ_MASK0_RD__ata_irq1__WIDTH 1 #define R_IRQ_MASK0_RD__ata_irq1__active 1 #define R_IRQ_MASK0_RD__ata_irq1__inactive 0 -#define R_IRQ_MASK0_RD__p21_irq1__BITNR 9 -#define R_IRQ_MASK0_RD__p21_irq1__WIDTH 1 -#define R_IRQ_MASK0_RD__p21_irq1__active 1 -#define R_IRQ_MASK0_RD__p21_irq1__inactive 0 #define R_IRQ_MASK0_RD__par0_ready__BITNR 8 #define R_IRQ_MASK0_RD__par0_ready__WIDTH 1 #define R_IRQ_MASK0_RD__par0_ready__active 1 @@ -3469,10 +3593,6 @@ #define R_IRQ_MASK0_RD__scsi0__WIDTH 1 #define R_IRQ_MASK0_RD__scsi0__active 1 #define R_IRQ_MASK0_RD__scsi0__inactive 0 -#define R_IRQ_MASK0_RD__p21_irq0__BITNR 8 -#define R_IRQ_MASK0_RD__p21_irq0__WIDTH 1 -#define R_IRQ_MASK0_RD__p21_irq0__active 1 -#define R_IRQ_MASK0_RD__p21_irq0__inactive 0 #define R_IRQ_MASK0_RD__ata_dmaend__BITNR 7 #define R_IRQ_MASK0_RD__ata_dmaend__WIDTH 1 #define R_IRQ_MASK0_RD__ata_dmaend__active 1 @@ -3599,10 +3719,6 @@ #define R_IRQ_MASK0_CLR__ata_irq2__WIDTH 1 #define R_IRQ_MASK0_CLR__ata_irq2__clr 1 #define R_IRQ_MASK0_CLR__ata_irq2__nop 0 -#define R_IRQ_MASK0_CLR__p21_irq2__BITNR 10 -#define R_IRQ_MASK0_CLR__p21_irq2__WIDTH 1 -#define R_IRQ_MASK0_CLR__p21_irq2__clr 1 -#define R_IRQ_MASK0_CLR__p21_irq2__nop 0 #define R_IRQ_MASK0_CLR__par0_data__BITNR 9 #define R_IRQ_MASK0_CLR__par0_data__WIDTH 1 #define R_IRQ_MASK0_CLR__par0_data__clr 1 @@ -3611,10 +3727,6 @@ #define R_IRQ_MASK0_CLR__ata_irq1__WIDTH 1 #define R_IRQ_MASK0_CLR__ata_irq1__clr 1 #define R_IRQ_MASK0_CLR__ata_irq1__nop 0 -#define R_IRQ_MASK0_CLR__p21_irq1__BITNR 9 -#define R_IRQ_MASK0_CLR__p21_irq1__WIDTH 1 -#define R_IRQ_MASK0_CLR__p21_irq1__clr 1 -#define R_IRQ_MASK0_CLR__p21_irq1__nop 0 #define R_IRQ_MASK0_CLR__par0_ready__BITNR 8 #define R_IRQ_MASK0_CLR__par0_ready__WIDTH 1 #define R_IRQ_MASK0_CLR__par0_ready__clr 1 @@ -3631,10 +3743,6 @@ #define R_IRQ_MASK0_CLR__scsi0__WIDTH 1 #define R_IRQ_MASK0_CLR__scsi0__clr 1 #define R_IRQ_MASK0_CLR__scsi0__nop 0 -#define R_IRQ_MASK0_CLR__p21_irq0__BITNR 8 -#define R_IRQ_MASK0_CLR__p21_irq0__WIDTH 1 -#define R_IRQ_MASK0_CLR__p21_irq0__clr 1 -#define R_IRQ_MASK0_CLR__p21_irq0__nop 0 #define R_IRQ_MASK0_CLR__ata_dmaend__BITNR 7 #define R_IRQ_MASK0_CLR__ata_dmaend__WIDTH 1 #define R_IRQ_MASK0_CLR__ata_dmaend__clr 1 @@ -3761,10 +3869,6 @@ #define R_IRQ_READ0__ata_irq2__WIDTH 1 #define R_IRQ_READ0__ata_irq2__active 1 #define R_IRQ_READ0__ata_irq2__inactive 0 -#define R_IRQ_READ0__p21_irq2__BITNR 10 -#define R_IRQ_READ0__p21_irq2__WIDTH 1 -#define R_IRQ_READ0__p21_irq2__active 1 -#define R_IRQ_READ0__p21_irq2__inactive 0 #define R_IRQ_READ0__par0_data__BITNR 9 #define R_IRQ_READ0__par0_data__WIDTH 1 #define R_IRQ_READ0__par0_data__active 1 @@ -3773,10 +3877,6 @@ #define R_IRQ_READ0__ata_irq1__WIDTH 1 #define R_IRQ_READ0__ata_irq1__active 1 #define R_IRQ_READ0__ata_irq1__inactive 0 -#define R_IRQ_READ0__p21_irq1__BITNR 9 -#define R_IRQ_READ0__p21_irq1__WIDTH 1 -#define R_IRQ_READ0__p21_irq1__active 1 -#define R_IRQ_READ0__p21_irq1__inactive 0 #define R_IRQ_READ0__par0_ready__BITNR 8 #define R_IRQ_READ0__par0_ready__WIDTH 1 #define R_IRQ_READ0__par0_ready__active 1 @@ -3793,10 +3893,6 @@ #define R_IRQ_READ0__scsi0__WIDTH 1 #define R_IRQ_READ0__scsi0__active 1 #define R_IRQ_READ0__scsi0__inactive 0 -#define R_IRQ_READ0__p21_irq0__BITNR 8 -#define R_IRQ_READ0__p21_irq0__WIDTH 1 -#define R_IRQ_READ0__p21_irq0__active 1 -#define R_IRQ_READ0__p21_irq0__inactive 0 #define R_IRQ_READ0__ata_dmaend__BITNR 7 #define R_IRQ_READ0__ata_dmaend__WIDTH 1 #define R_IRQ_READ0__ata_dmaend__active 1 @@ -3923,10 +4019,6 @@ #define R_IRQ_MASK0_SET__ata_irq2__WIDTH 1 #define R_IRQ_MASK0_SET__ata_irq2__set 1 #define R_IRQ_MASK0_SET__ata_irq2__nop 0 -#define R_IRQ_MASK0_SET__p21_irq2__BITNR 10 -#define R_IRQ_MASK0_SET__p21_irq2__WIDTH 1 -#define R_IRQ_MASK0_SET__p21_irq2__set 1 -#define R_IRQ_MASK0_SET__p21_irq2__nop 0 #define R_IRQ_MASK0_SET__par0_data__BITNR 9 #define R_IRQ_MASK0_SET__par0_data__WIDTH 1 #define R_IRQ_MASK0_SET__par0_data__set 1 @@ -3935,10 +4027,6 @@ #define R_IRQ_MASK0_SET__ata_irq1__WIDTH 1 #define R_IRQ_MASK0_SET__ata_irq1__set 1 #define R_IRQ_MASK0_SET__ata_irq1__nop 0 -#define R_IRQ_MASK0_SET__p21_irq1__BITNR 9 -#define R_IRQ_MASK0_SET__p21_irq1__WIDTH 1 -#define R_IRQ_MASK0_SET__p21_irq1__set 1 -#define R_IRQ_MASK0_SET__p21_irq1__nop 0 #define R_IRQ_MASK0_SET__par0_ready__BITNR 8 #define R_IRQ_MASK0_SET__par0_ready__WIDTH 1 #define R_IRQ_MASK0_SET__par0_ready__set 1 @@ -3955,10 +4043,6 @@ #define R_IRQ_MASK0_SET__scsi0__WIDTH 1 #define R_IRQ_MASK0_SET__scsi0__set 1 #define R_IRQ_MASK0_SET__scsi0__nop 0 -#define R_IRQ_MASK0_SET__p21_irq0__BITNR 8 -#define R_IRQ_MASK0_SET__p21_irq0__WIDTH 1 -#define R_IRQ_MASK0_SET__p21_irq0__set 1 -#define R_IRQ_MASK0_SET__p21_irq0__nop 0 #define R_IRQ_MASK0_SET__ata_dmaend__BITNR 7 #define R_IRQ_MASK0_SET__ata_dmaend__WIDTH 1 #define R_IRQ_MASK0_SET__ata_dmaend__set 1 @@ -4953,10 +5037,6 @@ #define R_VECT_MASK_RD__mio__WIDTH 1 #define R_VECT_MASK_RD__mio__active 1 #define R_VECT_MASK_RD__mio__inactive 0 -#define R_VECT_MASK_RD__p21__BITNR 4 -#define R_VECT_MASK_RD__p21__WIDTH 1 -#define R_VECT_MASK_RD__p21__active 1 -#define R_VECT_MASK_RD__p21__inactive 0 #define R_VECT_MASK_RD__timer1__BITNR 3 #define R_VECT_MASK_RD__timer1__WIDTH 1 #define R_VECT_MASK_RD__timer1__active 1 @@ -5075,10 +5155,6 @@ #define R_VECT_MASK_CLR__mio__WIDTH 1 #define R_VECT_MASK_CLR__mio__clr 1 #define R_VECT_MASK_CLR__mio__nop 0 -#define R_VECT_MASK_CLR__p21__BITNR 4 -#define R_VECT_MASK_CLR__p21__WIDTH 1 -#define R_VECT_MASK_CLR__p21__clr 1 -#define R_VECT_MASK_CLR__p21__nop 0 #define R_VECT_MASK_CLR__timer1__BITNR 3 #define R_VECT_MASK_CLR__timer1__WIDTH 1 #define R_VECT_MASK_CLR__timer1__clr 1 @@ -5197,10 +5273,6 @@ #define R_VECT_READ__mio__WIDTH 1 #define R_VECT_READ__mio__active 1 #define R_VECT_READ__mio__inactive 0 -#define R_VECT_READ__p21__BITNR 4 -#define R_VECT_READ__p21__WIDTH 1 -#define R_VECT_READ__p21__active 1 -#define R_VECT_READ__p21__inactive 0 #define R_VECT_READ__timer1__BITNR 3 #define R_VECT_READ__timer1__WIDTH 1 #define R_VECT_READ__timer1__active 1 @@ -5319,10 +5391,6 @@ #define R_VECT_MASK_SET__mio__WIDTH 1 #define R_VECT_MASK_SET__mio__set 1 #define R_VECT_MASK_SET__mio__nop 0 -#define R_VECT_MASK_SET__p21__BITNR 4 -#define R_VECT_MASK_SET__p21__WIDTH 1 -#define R_VECT_MASK_SET__p21__set 1 -#define R_VECT_MASK_SET__p21__nop 0 #define R_VECT_MASK_SET__timer1__BITNR 3 #define R_VECT_MASK_SET__timer1__WIDTH 1 #define R_VECT_MASK_SET__timer1__set 1 @@ -5997,6 +6065,10 @@ #define R_USB_COMMAND__port_cmd__disable 1 #define R_USB_COMMAND__port_cmd__suspend 2 #define R_USB_COMMAND__port_cmd__resume 3 +#define R_USB_COMMAND__busy__BITNR 3 +#define R_USB_COMMAND__busy__WIDTH 1 +#define R_USB_COMMAND__busy__no 0 +#define R_USB_COMMAND__busy__yes 1 #define R_USB_COMMAND__ctrl_cmd__BITNR 0 #define R_USB_COMMAND__ctrl_cmd__WIDTH 3 #define R_USB_COMMAND__ctrl_cmd__nop 0 @@ -6004,15 +6076,47 @@ #define R_USB_COMMAND__ctrl_cmd__deconfig 2 #define R_USB_COMMAND__ctrl_cmd__host_config 3 #define R_USB_COMMAND__ctrl_cmd__dev_config 4 -#define R_USB_COMMAND__ctrl_cmd__host_reset 5 +#define R_USB_COMMAND__ctrl_cmd__host_nop 5 #define R_USB_COMMAND__ctrl_cmd__host_run 6 #define R_USB_COMMAND__ctrl_cmd__host_stop 7 +#define R_USB_COMMAND_DEV (IO_TYPECAST_BYTE 0xb0000201) +#define R_USB_COMMAND_DEV__port_sel__BITNR 6 +#define R_USB_COMMAND_DEV__port_sel__WIDTH 2 +#define R_USB_COMMAND_DEV__port_sel__nop 0 +#define R_USB_COMMAND_DEV__port_sel__dummy1 1 +#define R_USB_COMMAND_DEV__port_sel__dummy2 2 +#define R_USB_COMMAND_DEV__port_sel__any 3 +#define R_USB_COMMAND_DEV__port_cmd__BITNR 4 +#define R_USB_COMMAND_DEV__port_cmd__WIDTH 2 +#define R_USB_COMMAND_DEV__port_cmd__active 0 +#define R_USB_COMMAND_DEV__port_cmd__passive 1 +#define R_USB_COMMAND_DEV__port_cmd__nop 2 +#define R_USB_COMMAND_DEV__port_cmd__wakeup 3 +#define R_USB_COMMAND_DEV__busy__BITNR 3 +#define R_USB_COMMAND_DEV__busy__WIDTH 1 +#define R_USB_COMMAND_DEV__busy__no 0 +#define R_USB_COMMAND_DEV__busy__yes 1 +#define R_USB_COMMAND_DEV__ctrl_cmd__BITNR 0 +#define R_USB_COMMAND_DEV__ctrl_cmd__WIDTH 3 +#define R_USB_COMMAND_DEV__ctrl_cmd__nop 0 +#define R_USB_COMMAND_DEV__ctrl_cmd__reset 1 +#define R_USB_COMMAND_DEV__ctrl_cmd__deconfig 2 +#define R_USB_COMMAND_DEV__ctrl_cmd__host_config 3 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_config 4 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_active 5 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_passive 6 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_nop 7 + #define R_USB_STATUS (IO_TYPECAST_RO_BYTE 0xb0000202) -#define R_USB_STATUS__busy__BITNR 7 -#define R_USB_STATUS__busy__WIDTH 1 -#define R_USB_STATUS__busy__no 0 -#define R_USB_STATUS__busy__yes 1 +#define R_USB_STATUS__ourun__BITNR 5 +#define R_USB_STATUS__ourun__WIDTH 1 +#define R_USB_STATUS__ourun__no 0 +#define R_USB_STATUS__ourun__yes 1 +#define R_USB_STATUS__perror__BITNR 4 +#define R_USB_STATUS__perror__WIDTH 1 +#define R_USB_STATUS__perror__no 0 +#define R_USB_STATUS__perror__yes 1 #define R_USB_STATUS__device_mode__BITNR 3 #define R_USB_STATUS__device_mode__WIDTH 1 #define R_USB_STATUS__device_mode__no 0 @@ -6031,30 +6135,34 @@ #define R_USB_STATUS__running__yes 1 #define R_USB_IRQ_MASK_SET (IO_TYPECAST_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 13 -#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_SET__intr_eof__nop 0 -#define R_USB_IRQ_MASK_SET__intr_eof__set 1 -#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 12 +#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 13 #define R_USB_IRQ_MASK_SET__iso_eof__WIDTH 1 #define R_USB_IRQ_MASK_SET__iso_eof__nop 0 #define R_USB_IRQ_MASK_SET__iso_eof__set 1 -#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 11 -#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0 -#define R_USB_IRQ_MASK_SET__bulk_eot__set 1 -#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 10 -#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0 -#define R_USB_IRQ_MASK_SET__ctl_eot__set 1 -#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 9 -#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__intr_eot__nop 0 -#define R_USB_IRQ_MASK_SET__intr_eot__set 1 -#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_SET__intr_eof__nop 0 +#define R_USB_IRQ_MASK_SET__intr_eof__set 1 +#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 11 #define R_USB_IRQ_MASK_SET__iso_eot__WIDTH 1 #define R_USB_IRQ_MASK_SET__iso_eot__nop 0 #define R_USB_IRQ_MASK_SET__iso_eot__set 1 +#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__intr_eot__nop 0 +#define R_USB_IRQ_MASK_SET__intr_eot__set 1 +#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0 +#define R_USB_IRQ_MASK_SET__ctl_eot__set 1 +#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0 +#define R_USB_IRQ_MASK_SET__bulk_eot__set 1 +#define R_USB_IRQ_MASK_SET__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_SET__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_SET__epid_attn__nop 0 +#define R_USB_IRQ_MASK_SET__epid_attn__set 1 #define R_USB_IRQ_MASK_SET__sof__BITNR 2 #define R_USB_IRQ_MASK_SET__sof__WIDTH 1 #define R_USB_IRQ_MASK_SET__sof__nop 0 @@ -6069,30 +6177,34 @@ #define R_USB_IRQ_MASK_SET__ctl_status__set 1 #define R_USB_IRQ_MASK_READ (IO_TYPECAST_RO_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 13 -#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0 -#define R_USB_IRQ_MASK_READ__intr_eof__pend 1 -#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 12 +#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 13 #define R_USB_IRQ_MASK_READ__iso_eof__WIDTH 1 #define R_USB_IRQ_MASK_READ__iso_eof__no_pend 0 #define R_USB_IRQ_MASK_READ__iso_eof__pend 1 -#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 11 -#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1 -#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 10 -#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1 -#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 9 -#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__intr_eot__pend 1 -#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0 +#define R_USB_IRQ_MASK_READ__intr_eof__pend 1 +#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 11 #define R_USB_IRQ_MASK_READ__iso_eot__WIDTH 1 #define R_USB_IRQ_MASK_READ__iso_eot__no_pend 0 #define R_USB_IRQ_MASK_READ__iso_eot__pend 1 +#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__intr_eot__pend 1 +#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1 +#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1 +#define R_USB_IRQ_MASK_READ__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_READ__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_READ__epid_attn__no_pend 0 +#define R_USB_IRQ_MASK_READ__epid_attn__pend 1 #define R_USB_IRQ_MASK_READ__sof__BITNR 2 #define R_USB_IRQ_MASK_READ__sof__WIDTH 1 #define R_USB_IRQ_MASK_READ__sof__no_pend 0 @@ -6107,30 +6219,34 @@ #define R_USB_IRQ_MASK_READ__ctl_status__pend 1 #define R_USB_IRQ_MASK_CLR (IO_TYPECAST_UWORD 0xb0000206) -#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 13 -#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0 -#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1 -#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 12 +#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 13 #define R_USB_IRQ_MASK_CLR__iso_eof__WIDTH 1 #define R_USB_IRQ_MASK_CLR__iso_eof__nop 0 #define R_USB_IRQ_MASK_CLR__iso_eof__clr 1 -#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 11 -#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 10 -#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 9 -#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0 +#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1 +#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 11 #define R_USB_IRQ_MASK_CLR__iso_eot__WIDTH 1 #define R_USB_IRQ_MASK_CLR__iso_eot__nop 0 #define R_USB_IRQ_MASK_CLR__iso_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_CLR__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__epid_attn__nop 0 +#define R_USB_IRQ_MASK_CLR__epid_attn__clr 1 #define R_USB_IRQ_MASK_CLR__sof__BITNR 2 #define R_USB_IRQ_MASK_CLR__sof__WIDTH 1 #define R_USB_IRQ_MASK_CLR__sof__nop 0 @@ -6145,30 +6261,34 @@ #define R_USB_IRQ_MASK_CLR__ctl_status__clr 1 #define R_USB_IRQ_READ (IO_TYPECAST_RO_UWORD 0xb0000206) -#define R_USB_IRQ_READ__intr_eof__BITNR 13 -#define R_USB_IRQ_READ__intr_eof__WIDTH 1 -#define R_USB_IRQ_READ__intr_eof__no_pend 0 -#define R_USB_IRQ_READ__intr_eof__pend 1 -#define R_USB_IRQ_READ__iso_eof__BITNR 12 +#define R_USB_IRQ_READ__iso_eof__BITNR 13 #define R_USB_IRQ_READ__iso_eof__WIDTH 1 #define R_USB_IRQ_READ__iso_eof__no_pend 0 #define R_USB_IRQ_READ__iso_eof__pend 1 -#define R_USB_IRQ_READ__bulk_eot__BITNR 11 -#define R_USB_IRQ_READ__bulk_eot__WIDTH 1 -#define R_USB_IRQ_READ__bulk_eot__no_pend 0 -#define R_USB_IRQ_READ__bulk_eot__pend 1 -#define R_USB_IRQ_READ__ctl_eot__BITNR 10 -#define R_USB_IRQ_READ__ctl_eot__WIDTH 1 -#define R_USB_IRQ_READ__ctl_eot__no_pend 0 -#define R_USB_IRQ_READ__ctl_eot__pend 1 -#define R_USB_IRQ_READ__intr_eot__BITNR 9 -#define R_USB_IRQ_READ__intr_eot__WIDTH 1 -#define R_USB_IRQ_READ__intr_eot__no_pend 0 -#define R_USB_IRQ_READ__intr_eot__pend 1 -#define R_USB_IRQ_READ__iso_eot__BITNR 8 +#define R_USB_IRQ_READ__intr_eof__BITNR 12 +#define R_USB_IRQ_READ__intr_eof__WIDTH 1 +#define R_USB_IRQ_READ__intr_eof__no_pend 0 +#define R_USB_IRQ_READ__intr_eof__pend 1 +#define R_USB_IRQ_READ__iso_eot__BITNR 11 #define R_USB_IRQ_READ__iso_eot__WIDTH 1 #define R_USB_IRQ_READ__iso_eot__no_pend 0 #define R_USB_IRQ_READ__iso_eot__pend 1 +#define R_USB_IRQ_READ__intr_eot__BITNR 10 +#define R_USB_IRQ_READ__intr_eot__WIDTH 1 +#define R_USB_IRQ_READ__intr_eot__no_pend 0 +#define R_USB_IRQ_READ__intr_eot__pend 1 +#define R_USB_IRQ_READ__ctl_eot__BITNR 9 +#define R_USB_IRQ_READ__ctl_eot__WIDTH 1 +#define R_USB_IRQ_READ__ctl_eot__no_pend 0 +#define R_USB_IRQ_READ__ctl_eot__pend 1 +#define R_USB_IRQ_READ__bulk_eot__BITNR 8 +#define R_USB_IRQ_READ__bulk_eot__WIDTH 1 +#define R_USB_IRQ_READ__bulk_eot__no_pend 0 +#define R_USB_IRQ_READ__bulk_eot__pend 1 +#define R_USB_IRQ_READ__epid_attn__BITNR 3 +#define R_USB_IRQ_READ__epid_attn__WIDTH 1 +#define R_USB_IRQ_READ__epid_attn__no_pend 0 +#define R_USB_IRQ_READ__epid_attn__pend 1 #define R_USB_IRQ_READ__sof__BITNR 2 #define R_USB_IRQ_READ__sof__WIDTH 1 #define R_USB_IRQ_READ__sof__no_pend 0 @@ -6182,7 +6302,159 @@ #define R_USB_IRQ_READ__ctl_status__no_pend 0 #define R_USB_IRQ_READ__ctl_status__pend 1 -#define R_USB_FM_NUMBER (IO_TYPECAST_RO_UDWORD 0xb000020c) +#define R_USB_IRQ_MASK_SET_DEV (IO_TYPECAST_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_SET_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__set 1 +#define R_USB_IRQ_MASK_SET_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_SET_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__sof__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__sof__set 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__port_status__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__set 1 + +#define R_USB_IRQ_MASK_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_READ_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_READ_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__sof__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__sof__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__port_status__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__pend 1 + +#define R_USB_IRQ_MASK_CLR_DEV (IO_TYPECAST_UWORD 0xb0000206) +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_CLR_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__sof__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__sof__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__clr 1 + +#define R_USB_IRQ_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000206) +#define R_USB_IRQ_READ_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_READ_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__out_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__out_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_READ_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_READ_DEV__epid_attn__no_pend 0 +#define R_USB_IRQ_READ_DEV__epid_attn__pend 1 +#define R_USB_IRQ_READ_DEV__sof__BITNR 2 +#define R_USB_IRQ_READ_DEV__sof__WIDTH 1 +#define R_USB_IRQ_READ_DEV__sof__no_pend 0 +#define R_USB_IRQ_READ_DEV__sof__pend 1 +#define R_USB_IRQ_READ_DEV__port_status__BITNR 1 +#define R_USB_IRQ_READ_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_READ_DEV__port_status__no_pend 0 +#define R_USB_IRQ_READ_DEV__port_status__pend 1 +#define R_USB_IRQ_READ_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_READ_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ctl_status__no_pend 0 +#define R_USB_IRQ_READ_DEV__ctl_status__pend 1 + +#define R_USB_FM_NUMBER (IO_TYPECAST_UDWORD 0xb000020c) #define R_USB_FM_NUMBER__value__BITNR 0 #define R_USB_FM_NUMBER__value__WIDTH 32 @@ -6200,22 +6472,26 @@ #define R_USB_FM_PSTART__value__BITNR 0 #define R_USB_FM_PSTART__value__WIDTH 14 -#define R_USB_LS_THRESHOLD (IO_TYPECAST_UWORD 0xb0000216) -#define R_USB_LS_THRESHOLD__value__BITNR 0 -#define R_USB_LS_THRESHOLD__value__WIDTH 14 - #define R_USB_RH_STATUS (IO_TYPECAST_RO_BYTE 0xb0000203) +#define R_USB_RH_STATUS__babble2__BITNR 7 +#define R_USB_RH_STATUS__babble2__WIDTH 1 +#define R_USB_RH_STATUS__babble2__no 0 +#define R_USB_RH_STATUS__babble2__yes 1 +#define R_USB_RH_STATUS__babble1__BITNR 6 +#define R_USB_RH_STATUS__babble1__WIDTH 1 +#define R_USB_RH_STATUS__babble1__no 0 +#define R_USB_RH_STATUS__babble1__yes 1 #define R_USB_RH_STATUS__bus1__BITNR 4 #define R_USB_RH_STATUS__bus1__WIDTH 2 #define R_USB_RH_STATUS__bus1__SE0 0 #define R_USB_RH_STATUS__bus1__Diff0 1 -#define R_USB_RH_STATUS__bus1__Diff1 1 +#define R_USB_RH_STATUS__bus1__Diff1 2 #define R_USB_RH_STATUS__bus1__SE1 3 #define R_USB_RH_STATUS__bus2__BITNR 2 #define R_USB_RH_STATUS__bus2__WIDTH 2 #define R_USB_RH_STATUS__bus2__SE0 0 #define R_USB_RH_STATUS__bus2__Diff0 1 -#define R_USB_RH_STATUS__bus2__Diff1 1 +#define R_USB_RH_STATUS__bus2__Diff1 2 #define R_USB_RH_STATUS__bus2__SE1 3 #define R_USB_RH_STATUS__nports__BITNR 0 #define R_USB_RH_STATUS__nports__WIDTH 2 @@ -6231,10 +6507,10 @@ #define R_USB_RH_PORT_STATUS_1__reset__WIDTH 1 #define R_USB_RH_PORT_STATUS_1__reset__no 0 #define R_USB_RH_PORT_STATUS_1__reset__yes 1 -#define R_USB_RH_PORT_STATUS_1__overcurent__BITNR 3 -#define R_USB_RH_PORT_STATUS_1__overcurent__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__overcurent__no 0 -#define R_USB_RH_PORT_STATUS_1__overcurent__yes 1 +#define R_USB_RH_PORT_STATUS_1__overcurrent__BITNR 3 +#define R_USB_RH_PORT_STATUS_1__overcurrent__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__overcurrent__no 0 +#define R_USB_RH_PORT_STATUS_1__overcurrent__yes 1 #define R_USB_RH_PORT_STATUS_1__suspended__BITNR 2 #define R_USB_RH_PORT_STATUS_1__suspended__WIDTH 1 #define R_USB_RH_PORT_STATUS_1__suspended__no 0 @@ -6259,10 +6535,10 @@ #define R_USB_RH_PORT_STATUS_2__reset__WIDTH 1 #define R_USB_RH_PORT_STATUS_2__reset__no 0 #define R_USB_RH_PORT_STATUS_2__reset__yes 1 -#define R_USB_RH_PORT_STATUS_2__overcurent__BITNR 3 -#define R_USB_RH_PORT_STATUS_2__overcurent__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__overcurent__no 0 -#define R_USB_RH_PORT_STATUS_2__overcurent__yes 1 +#define R_USB_RH_PORT_STATUS_2__overcurrent__BITNR 3 +#define R_USB_RH_PORT_STATUS_2__overcurrent__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__overcurrent__no 0 +#define R_USB_RH_PORT_STATUS_2__overcurrent__yes 1 #define R_USB_RH_PORT_STATUS_2__suspended__BITNR 2 #define R_USB_RH_PORT_STATUS_2__suspended__WIDTH 1 #define R_USB_RH_PORT_STATUS_2__suspended__no 0 @@ -6308,7 +6584,7 @@ #define R_USB_EPT_DATA__error_code__no_error 0 #define R_USB_EPT_DATA__error_code__stall 1 #define R_USB_EPT_DATA__error_code__bus_error 2 -#define R_USB_EPT_DATA__error_code__TBD3 3 +#define R_USB_EPT_DATA__error_code__buffer_error 3 #define R_USB_EPT_DATA__t_out__BITNR 21 #define R_USB_EPT_DATA__t_out__WIDTH 1 #define R_USB_EPT_DATA__error_count_out__BITNR 19 @@ -6357,10 +6633,10 @@ #define R_USB_EPT_DATA_DEV__stall__WIDTH 1 #define R_USB_EPT_DATA_DEV__stall__no 0 #define R_USB_EPT_DATA_DEV__stall__yes 1 -#define R_USB_EPT_DATA_DEV__quiet__BITNR 28 -#define R_USB_EPT_DATA_DEV__quiet__WIDTH 1 -#define R_USB_EPT_DATA_DEV__quiet__no 0 -#define R_USB_EPT_DATA_DEV__quiet__yes 1 +#define R_USB_EPT_DATA_DEV__iso_resp__BITNR 28 +#define R_USB_EPT_DATA_DEV__iso_resp__WIDTH 1 +#define R_USB_EPT_DATA_DEV__iso_resp__quiet 0 +#define R_USB_EPT_DATA_DEV__iso_resp__yes 1 #define R_USB_EPT_DATA_DEV__ctrl__BITNR 27 #define R_USB_EPT_DATA_DEV__ctrl__WIDTH 1 #define R_USB_EPT_DATA_DEV__ctrl__no 0 @@ -6371,6 +6647,8 @@ #define R_USB_EPT_DATA_DEV__iso__yes 1 #define R_USB_EPT_DATA_DEV__port__BITNR 24 #define R_USB_EPT_DATA_DEV__port__WIDTH 2 +#define R_USB_EPT_DATA_DEV__control_phase__BITNR 22 +#define R_USB_EPT_DATA_DEV__control_phase__WIDTH 1 #define R_USB_EPT_DATA_DEV__t__BITNR 21 #define R_USB_EPT_DATA_DEV__t__WIDTH 1 #define R_USB_EPT_DATA_DEV__max_len__BITNR 11 @@ -6384,6 +6662,22 @@ #define R_USB_SNMP_TERROR__value__BITNR 0 #define R_USB_SNMP_TERROR__value__WIDTH 32 +#define R_USB_EPID_ATTN (IO_TYPECAST_RO_UDWORD 0xb0000224) +#define R_USB_EPID_ATTN__value__BITNR 0 +#define R_USB_EPID_ATTN__value__WIDTH 32 + +#define R_USB_PORT1_DISABLE (IO_TYPECAST_BYTE 0xb000006a) +#define R_USB_PORT1_DISABLE__disable__BITNR 0 +#define R_USB_PORT1_DISABLE__disable__WIDTH 1 +#define R_USB_PORT1_DISABLE__disable__yes 0 +#define R_USB_PORT1_DISABLE__disable__no 1 + +#define R_USB_PORT2_DISABLE (IO_TYPECAST_BYTE 0xb0000052) +#define R_USB_PORT2_DISABLE__disable__BITNR 0 +#define R_USB_PORT2_DISABLE__disable__WIDTH 1 +#define R_USB_PORT2_DISABLE__disable__yes 0 +#define R_USB_PORT2_DISABLE__disable__no 1 + /* !* MMU registers !*/ @@ -6615,6 +6909,10 @@ #define R_MMU_CAUSE__we_excp__WIDTH 1 #define R_MMU_CAUSE__we_excp__yes 1 #define R_MMU_CAUSE__we_excp__no 0 +#define R_MMU_CAUSE__wr_rd__BITNR 8 +#define R_MMU_CAUSE__wr_rd__WIDTH 1 +#define R_MMU_CAUSE__wr_rd__write 1 +#define R_MMU_CAUSE__wr_rd__read 0 #define R_MMU_CAUSE__page_id__BITNR 0 #define R_MMU_CAUSE__page_id__WIDTH 6 diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/sync_serial.h linux/include/asm-cris/sync_serial.h --- v2.4.3/linux/include/asm-cris/sync_serial.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-cris/sync_serial.h Fri Apr 6 10:51:19 2001 @@ -0,0 +1,97 @@ +/* + * ioctl defines for synchrnous serial port driver + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Mikael Starvik + * + */ + +#ifndef SYNC_SERIAL_H +#define SYNC_SERIAL_H + +#include <linux/ioctl.h> + +#define SSP_SPEED _IOR('S', 0, unsigned int) +#define SSP_MODE _IOR('S', 1, unsigned int) +#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int) +#define SSP_IPOLARITY _IOR('S', 3, unsigned int) +#define SSP_OPOLARITY _IOR('S', 4, unsigned int) +#define SSP_SPI _IOR('S', 5, unsigned int) + +/* Values for SSP_SPEED */ +#define SSP150 0 +#define SSP300 1 +#define SSP600 2 +#define SSP1200 3 +#define SSP2400 4 +#define SSP4800 5 +#define SSP9600 6 +#define SSP19200 7 +#define SSP28800 8 +#define SSP57600 9 +#define SSP115200 10 +#define SSP230400 11 +#define SSP460800 12 +#define SSP921600 13 +#define SSP3125000 14 +#define CODEC 15 + +#define FREQ_4MHz 0 +#define FREQ_2MHz 1 +#define FREQ_1MHz 2 +#define FREQ_512kHz 3 +#define FREQ_256kHz 4 +#define FREQ_128kHz 5 +#define FREQ_64kHz 6 +#define FREQ_32kHz 7 + +/* Used by application to set CODEC divider, word rate and frame rate */ +#define CODEC_VAL(freq, word, frame) (CODEC | (freq << 8) | (word << 16) | (frame << 28)) + +/* Used by driver to extract speed */ +#define GET_SPEED(x) (x & 0xff) +#define GET_FREQ(x) ((x & 0xff00) >> 8) +#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1) +#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1) + +/* Values for SSP_MODE */ +#define MASTER_OUTPUT 0 +#define SLAVE_OUTPUT 1 +#define MASTER_INPUT 2 +#define SLAVE_INPUT 3 +#define MASTER_BIDIR 4 +#define SLAVE_BIDIR 5 + +/* Values for SSP_FRAME_SYNC */ +#define NORMAL_SYNC 1 +#define EARLY_SYNC 2 +#define BIT_SYNC 4 +#define WORD_SYNC 8 +#define EXTENDED_SYNC 0x10 +#define SYNC_OFF 0x20 +#define SYNC_ON 0x40 +#define WORD_SIZE_8 0x80 +#define WORD_SIZE_12 0x100 +#define WORD_SIZE_16 0x200 +#define WORD_SIZE_24 0x300 +#define WORD_SIZE_32 0x800 +#define BIT_ORDER_LSB 0x1000 +#define BIT_ORDER_MSB 0x2000 +#define FLOW_CONTROL_ENABLE 0x4000 +#define FLOW_CONTROL_DISABLE 0x8000 +#define CLOCK_GATED 0x10000 +#define CLOCK_NOT_GATED 0x20000 + +/* Values for SSP_IPOLARITY and SSP_OPOLARITY */ +#define CLOCK_NORMAL 1 +#define CLOCK_INVERT 2 +#define FRAME_NORMAL 4 +#define FRAME_INVERT 8 +#define STATUS_NORMAL 0x10 +#define STATUS_INVERT 0x20 + +/* Values for SSP_SPI */ +#define SPI_MASTER 0 +#define SPI_SLAVE 1 +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/termios.h linux/include/asm-cris/termios.h --- v2.4.3/linux/include/asm-cris/termios.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/termios.h Fri Apr 6 10:51:19 2001 @@ -51,7 +51,7 @@ #define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ -#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ #define N_SYNC_PPP 14 /* synchronous PPP */ diff -u --recursive --new-file v2.4.3/linux/include/asm-cris/unistd.h linux/include/asm-cris/unistd.h --- v2.4.3/linux/include/asm-cris/unistd.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/unistd.h Fri Apr 6 10:51:19 2001 @@ -233,28 +233,28 @@ type name(void) \ { \ register long __a __asm__ ("r10"); \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ register long __a __asm__ ("r10") = (long) arg1; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall2(type,name,type1,arg1,type2,arg2) \ @@ -262,14 +262,14 @@ { \ register long __a __asm__ ("r10") = (long) arg1; \ register long __b __asm__ ("r11") = (long) arg2; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ @@ -278,14 +278,14 @@ register long __a __asm__ ("r10") = (long) arg1; \ register long __b __asm__ ("r11") = (long) arg2; \ register long __c __asm__ ("r12") = (long) arg3; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ @@ -295,15 +295,15 @@ register long __b __asm__ ("r11") = (long) arg2; \ register long __c __asm__ ("r12") = (long) arg3; \ register long __d __asm__ ("r13") = (long) arg4; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b), \ "r" (__c), "r" (__d) \ - : "r10", "r1"); \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ } #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ @@ -314,16 +314,36 @@ register long __b __asm__ ("r11") = (long) arg2; \ register long __c __asm__ ("r12") = (long) arg3; \ register long __d __asm__ ("r13") = (long) arg4; \ - register long __e __asm__ ("r0") = (long) arg5; \ - __asm__ __volatile__ ("move.d %1,r1\n\tbreak 13" \ + __asm__ __volatile__ ("move %6,$mof\n\t" \ + "movu.w %1,$r9\n\tbreak 13" \ : "=r" (__a) \ : "g" (__NR_##name), "0" (__a), "r" (__b), \ - "r" (__c), "r" (__d), "r" (__e) \ - : "r10", "r1"); \ + "r" (__c), "r" (__d), "g" (arg5) \ + : "r10", "r9"); \ if(__a >= 0) \ return (type) __a; \ errno = -__a; \ - return -1; \ + return (type) -1; \ +} + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \ + "movu.w %1,$r9\n\tbreak 13" \ + : "=r" (__a) \ + : "g" (__NR_##name), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\ + : "r10", "r9", "srp"); \ + if(__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ } #ifdef __KERNEL_SYSCALLS__ diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v2.4.3/linux/include/asm-i386/atomic.h Mon Mar 26 15:48:10 2001 +++ linux/include/asm-i386/atomic.h Tue Apr 17 14:43:30 2001 @@ -75,7 +75,7 @@ } /** - * atomic_sub_and_test - test variable then subtract + * atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract * @v: pointer of type atomic_t * @@ -111,7 +111,7 @@ } /** - * atomic_dec - decrement the atomic variable + * atomic_dec - decrement atomic variable * @v: pointer of type atomic_t * * Atomically decrements @v by 1. Note that the guaranteed @@ -126,7 +126,7 @@ } /** - * atomic_dec_and_test - decrement by 1 and test + * atomic_dec_and_test - decrement and test * @v: pointer of type atomic_t * * Atomically decrements @v by 1 and @@ -146,7 +146,7 @@ } /** - * atomic_inc_and_test - increment by 1 and test + * atomic_inc_and_test - increment and test * @v: pointer of type atomic_t * * Atomically increments @v by 1 diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- v2.4.3/linux/include/asm-i386/bitops.h Mon Mar 26 15:48:10 2001 +++ linux/include/asm-i386/bitops.h Tue Apr 17 14:43:32 2001 @@ -23,6 +23,16 @@ #define ADDR (*(volatile long *) addr) +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ static __inline__ void set_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX @@ -31,7 +41,15 @@ :"Ir" (nr)); } -/* WARNING: non atomic and it can be reordered! */ +/** + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ static __inline__ void __set_bit(int nr, volatile void * addr) { __asm__( @@ -40,11 +58,16 @@ :"Ir" (nr)); } -/* - * clear_bit() doesn't provide any barrier for the compiler. +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() static __inline__ void clear_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX @@ -52,7 +75,18 @@ :"=m" (ADDR) :"Ir" (nr)); } +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ static __inline__ void change_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX @@ -61,10 +95,13 @@ :"Ir" (nr)); } -/* - * It will also imply a memory barrier, thus it must clobber memory - * to make sure to reload anything that was cached into registers - * outside _this_ critical section. +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. */ static __inline__ int test_and_set_bit(int nr, volatile void * addr) { @@ -77,7 +114,15 @@ return oldbit; } -/* WARNING: non atomic and it can be reordered! */ +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ static __inline__ int __test_and_set_bit(int nr, volatile void * addr) { int oldbit; @@ -89,6 +134,14 @@ return oldbit; } +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ static __inline__ int test_and_clear_bit(int nr, volatile void * addr) { int oldbit; @@ -100,7 +153,15 @@ return oldbit; } -/* WARNING: non atomic and it can be reordered! */ +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) { int oldbit; @@ -112,6 +173,14 @@ return oldbit; } +/** + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ static __inline__ int test_and_change_bit(int nr, volatile void * addr) { int oldbit; @@ -123,9 +192,15 @@ return oldbit; } -/* - * This routine doesn't need to be atomic. +#if 0 /* Fool kernel-doc since it doesn't do macros yet */ +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from */ +static int test_bit(int nr, const volatile void * addr); +#endif + static __inline__ int constant_test_bit(int nr, const volatile void * addr) { return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; @@ -147,8 +222,13 @@ constant_test_bit((nr),(addr)) : \ variable_test_bit((nr),(addr))) -/* - * Find-bit routines.. +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. */ static __inline__ int find_first_zero_bit(void * addr, unsigned size) { @@ -174,6 +254,12 @@ return res; } +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ static __inline__ int find_next_zero_bit (void * addr, int size, int offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 5); @@ -201,9 +287,11 @@ return (offset + set + res); } -/* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. +/** + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. */ static __inline__ unsigned long ffz(unsigned long word) { @@ -215,12 +303,14 @@ #ifdef __KERNEL__ -/* - * ffs: find first bit set. This is defined the same way as +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ - static __inline__ int ffs(int x) { int r; @@ -232,9 +322,11 @@ return r+1; } -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word +/** + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. */ #define hweight32(x) generic_hweight32(x) diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/io.h linux/include/asm-i386/io.h --- v2.4.3/linux/include/asm-i386/io.h Mon Mar 26 15:48:21 2001 +++ linux/include/asm-i386/io.h Tue Apr 17 14:44:10 2001 @@ -111,7 +111,7 @@ * Temporary debugging check to catch old code using * unmapped ISA addresses. Will be removed in 2.4. */ -#if 1 +#if 0 extern void *__io_virt_debug(unsigned long x, const char *file, int line); extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line); #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__) diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/kmap_types.h linux/include/asm-i386/kmap_types.h --- v2.4.3/linux/include/asm-i386/kmap_types.h Thu Nov 11 10:33:42 1999 +++ linux/include/asm-i386/kmap_types.h Thu Apr 12 12:11:39 2001 @@ -4,6 +4,8 @@ enum km_type { KM_BOUNCE_READ, KM_BOUNCE_WRITE, + KM_SKB_DATA, + KM_SKB_DATA_SOFTIRQ, KM_TYPE_NR }; diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/rwsem-spin.h linux/include/asm-i386/rwsem-spin.h --- v2.4.3/linux/include/asm-i386/rwsem-spin.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-i386/rwsem-spin.h Tue Apr 17 17:19:31 2001 @@ -0,0 +1,322 @@ +/* rwsem.h: R/W semaphores based on spinlocks + * + * Written by David Howells (dhowells@redhat.com). + * + * Derived from asm-i386/semaphore.h and asm-i386/spinlock.h + */ + +#ifndef _I386_RWSEM_SPIN_H +#define _I386_RWSEM_SPIN_H + +#include <linux/config.h> + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem-spin.h directly, use linux/rwsem.h instead +#endif + +#include <linux/spinlock.h> + +#ifdef __KERNEL__ + +/* + * the semaphore definition + */ +struct rw_semaphore { + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t lock; +#define RWSEM_SPINLOCK_OFFSET_STR "4" /* byte offset of spinlock */ + wait_queue_head_t wait; +#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0 /* bits to use in wait_queue_t.flags */ +#define RWSEM_WAITING_FOR_WRITE WQ_FLAG_CONTEXT_1 +#if RWSEM_DEBUG + int debug; +#endif +#if RWSEM_DEBUG_MAGIC + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +/* + * initialisation + */ +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif +#if RWSEM_DEBUG_MAGIC +#define __RWSEM_DEBUG_MINIT(name) , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_MINIT(name) /* */ +#endif + +#define __RWSEM_INITIALIZER(name,count) \ +{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) } + +#define __DECLARE_RWSEM_GENERIC(name,count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) + +#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->lock); + init_waitqueue_head(&sem->wait); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +#if RWSEM_DEBUG_MAGIC + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning down_read\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " js 4f\n\t" /* jump if we weren't granted the lock */ + "2:\n" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " call __rwsem_down_read_failed\n\t" + " jmp 2b\n" + ".previous" + "# ending __down_read\n\t" + : "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int tmp; + + tmp = RWSEM_ACTIVE_WRITE_BIAS; + __asm__ __volatile__( + "# beginning down_write\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " xchg %0,(%%eax)\n\t" /* retrieve the old value */ + " add %0,(%%eax)\n\t" /* add 0xffff0001, result in memory */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " testl %0,%0\n\t" /* was the count 0 before? */ + " jnz 4f\n\t" /* jump if we weren't granted the lock */ + "2:\n\t" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " call __rwsem_down_write_failed\n\t" + " jmp 2b\n" + ".previous\n" + "# ending down_write" + : "+r"(tmp), "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int tmp; + + tmp = -RWSEM_ACTIVE_READ_BIAS; + __asm__ __volatile__( + "# beginning __up_read\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " xchg %0,(%%eax)\n\t" /* retrieve the old value */ + " addl %0,(%%eax)\n\t" /* subtract 1, result in memory */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " js 4f\n\t" /* jump if the lock is being waited upon */ + "2:\n\t" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " decl %0\n\t" /* xchg gave us the old count */ + " testl %4,%0\n\t" /* do nothing if still outstanding active readers */ + " jnz 2b\n\t" + " call __rwsem_wake\n\t" + " jmp 2b\n" + ".previous\n" + "# ending __up_read\n" + : "+r"(tmp), "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning __up_write\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " addl %3,(%%eax)\n\t" /* adds 0x00010001 */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */ +#endif + " js 4f\n\t" /* jump if the lock is being waited upon */ + "2:\n\t" + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " call __rwsem_wake\n\t" + " jmp 2b\n" + ".previous\n" + "# ending __up_write\n" + : "=m"(sem->count), "=m"(sem->lock) + : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count), "m"(sem->lock) + : "memory"); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + int tmp = delta; + + __asm__ __volatile__( + "# beginning rwsem_atomic_update\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " xchgl %0,(%1)\n\t" /* retrieve the old value */ + " addl %0,(%1)\n\t" /* add 0xffff0001, result in memory */ +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" /* release the spinlock */ +#endif + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + ".previous\n" + "# ending rwsem_atomic_update\n\t" + : "+r"(tmp) + : "r"(sem) + : "memory"); + + return tmp+delta; +} + +/* + * implement compare and exchange functionality on the rw-semaphore count LSW + */ +static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new) +{ + __u16 prev; + + __asm__ __volatile__( + "# beginning rwsem_cmpxchgw\n\t" +#ifdef CONFIG_SMP +LOCK_PREFIX " decb "RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" /* try to grab the spinlock */ + " js 3f\n" /* jump if failed */ + "1:\n\t" +#endif + " cmpw %w1,(%3)\n\t" + " jne 4f\n\t" /* jump if old doesn't match sem->count LSW */ + " movw %w2,(%3)\n\t" /* replace sem->count LSW with the new value */ + "2:\n\t" +#ifdef CONFIG_SMP + " movb $1,"RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" /* release the spinlock */ +#endif + ".section .text.lock,\"ax\"\n" +#ifdef CONFIG_SMP + "3:\n\t" /* spin on the spinlock till we get it */ + " cmpb $0,"RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" + " rep;nop \n\t" + " jle 3b\n\t" + " jmp 1b\n" +#endif + "4:\n\t" + " movw (%3),%w0\n" /* we'll want to return the current value */ + " jmp 2b\n" + ".previous\n" + "# ending rwsem_cmpxchgw\n\t" + : "=r"(prev) + : "r0"(old), "r"(new), "r"(sem) + : "memory"); + + return prev; +} + +#endif /* __KERNEL__ */ +#endif /* _I386_RWSEM_SPIN_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/rwsem-xadd.h linux/include/asm-i386/rwsem-xadd.h --- v2.4.3/linux/include/asm-i386/rwsem-xadd.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-i386/rwsem-xadd.h Thu Apr 12 12:22:53 2001 @@ -0,0 +1,198 @@ +/* rwsem-xadd.h: R/W semaphores implemented using XADD/CMPXCHG + * + * Written by David Howells (dhowells@redhat.com), 2001. + * Derived from asm-i386/semaphore.h + */ + +#ifndef _I386_RWSEM_XADD_H +#define _I386_RWSEM_XADD_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem-xadd.h directly, use linux/rwsem.h instead +#endif + +#ifdef __KERNEL__ + +/* + * the semaphore definition + */ +struct rw_semaphore { + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + wait_queue_head_t wait; +#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0 /* bits to use in wait_queue_t.flags */ +#define RWSEM_WAITING_FOR_WRITE WQ_FLAG_CONTEXT_1 +#if RWSEM_DEBUG + int debug; +#endif +#if RWSEM_DEBUG_MAGIC + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +/* + * initialisation + */ +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif +#if RWSEM_DEBUG_MAGIC +#define __RWSEM_DEBUG_MINIT(name) , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_MINIT(name) /* */ +#endif + +#define __RWSEM_INITIALIZER(name,count) \ +{ RWSEM_UNLOCKED_VALUE, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) } + +#define __DECLARE_RWSEM_GENERIC(name,count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) + +#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + init_waitqueue_head(&sem->wait); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +#if RWSEM_DEBUG_MAGIC + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning down_read\n\t" +LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */ + " js 2f\n\t" /* jump if we weren't granted the lock */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " call __rwsem_down_read_failed\n\t" + " jmp 1b\n" + ".previous" + "# ending down_read\n\t" + : "=m"(sem->count) + : "a"(sem), "m"(sem->count) + : "memory"); +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int tmp; + + tmp = RWSEM_ACTIVE_WRITE_BIAS; + __asm__ __volatile__( + "# beginning down_write\n\t" +LOCK_PREFIX " xadd %0,(%%eax)\n\t" /* subtract 0x00010001, returns the old value */ + " testl %0,%0\n\t" /* was the count 0 before? */ + " jnz 2f\n\t" /* jump if we weren't granted the lock */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " call __rwsem_down_write_failed\n\t" + " jmp 1b\n" + ".previous\n" + "# ending down_write" + : "+r"(tmp), "=m"(sem->count) + : "a"(sem), "m"(sem->count) + : "memory"); +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int tmp; + + tmp = -RWSEM_ACTIVE_READ_BIAS; + __asm__ __volatile__( + "# beginning __up_read\n\t" +LOCK_PREFIX " xadd %0,(%%eax)\n\t" /* subtracts 1, returns the old value */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " decl %0\n\t" /* xadd gave us the old count */ + " testl %3,%0\n\t" /* do nothing if still outstanding active readers */ + " jnz 1b\n\t" + " call __rwsem_wake\n\t" + " jmp 1b\n" + ".previous\n" + "# ending __up_read\n" + : "+r"(tmp), "=m"(sem->count) + : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count) + : "memory"); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "# beginning __up_write\n\t" +LOCK_PREFIX " addl %2,(%%eax)\n\t" /* adds 0x0000ffff */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + ".section .text.lock,\"ax\"\n" + "2:\n\t" + " call __rwsem_wake\n\t" + " jmp 1b\n" + ".previous\n" + "# ending __up_write\n" + : "=m"(sem->count) + : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count) + : "memory"); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + int tmp = delta; + + __asm__ __volatile__( + LOCK_PREFIX "xadd %0,(%1)" + : "+r"(tmp) + : "r"(sem) + : "memory"); + + return tmp+delta; +} + +/* + * implement compare and exchange functionality on the rw-semaphore count LSW + */ +static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new) +{ + return cmpxchg((__u16*)&sem->count,0,RWSEM_ACTIVE_BIAS); +} + +#endif /* __KERNEL__ */ +#endif /* _I386_RWSEM_XADD_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/rwsem.h linux/include/asm-i386/rwsem.h --- v2.4.3/linux/include/asm-i386/rwsem.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-i386/rwsem.h Tue Apr 17 17:19:31 2001 @@ -0,0 +1,29 @@ +/* rwsem.h: R/W semaphores optimised using i386 assembly + * + * Written by David Howells (dhowells@redhat.com). + * + * Derived from asm-i386/semaphore.h + */ + +#ifndef _I386_RWSEM_H +#define _I386_RWSEM_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead +#endif + +#ifdef __KERNEL__ + +#ifdef CONFIG_X86_XADD +#include <asm/rwsem-xadd.h> /* use XADD based semaphores if possible */ +#else +#include <asm/rwsem-spin.h> /* use optimised spinlock based semaphores otherwise */ +#endif + +/* we use FASTCALL convention for the helpers */ +extern struct rw_semaphore *FASTCALL(__rwsem_down_read_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(__rwsem_down_write_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); + +#endif /* __KERNEL__ */ +#endif /* _I386_RWSEM_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h --- v2.4.3/linux/include/asm-i386/semaphore.h Mon Mar 26 15:48:11 2001 +++ linux/include/asm-i386/semaphore.h Tue Apr 17 14:43:44 2001 @@ -38,8 +38,8 @@ #include <asm/system.h> #include <asm/atomic.h> -#include <asm/rwlock.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -202,184 +202,6 @@ :"=m" (sem->count) :"c" (sem) :"memory"); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subl'ing - * BIAS once per CPU will result in the long remaining - * negative. - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned char write_bias_granted; - volatile unsigned char read_bias_granted; - volatile unsigned char pad1; - volatile unsigned char pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -/* we use FASTCALL convention for the helpers */ -extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem)); -extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem)); -extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); - -static inline void down_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - __build_read_lock(sem, "__down_read_failed"); -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -static inline void down_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - __build_write_lock(sem, "__down_write_failed"); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -static inline void __up_read(struct rw_semaphore *sem) -{ - __asm__ __volatile__( - "# up_read\n\t" - LOCK "incl %0\n\t" - "jz 2f\n" /* only do the wake if result == 0 (ie, a writer) */ - "1:\n\t" - ".section .text.lock,\"ax\"\n" - "2:\tcall __rwsem_wake\n\t" - "jmp 1b\n" - ".previous" - :"=m" (sem->count) - :"a" (sem) - :"memory" - ); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -static inline void __up_write(struct rw_semaphore *sem) -{ - __asm__ __volatile__( - "# up_write\n\t" - LOCK "addl $" RW_LOCK_BIAS_STR ",%0\n" - "jc 2f\n" /* only do the wake if the result was -'ve to 0/+'ve */ - "1:\n\t" - ".section .text.lock,\"ax\"\n" - "2:\tcall __rwsem_wake\n\t" - "jmp 1b\n" - ".previous" - :"=m" (sem->count) - :"a" (sem) - :"memory" - ); -} - -static inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -static inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); } #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-i386/string.h linux/include/asm-i386/string.h --- v2.4.3/linux/include/asm-i386/string.h Mon Mar 26 15:48:10 2001 +++ linux/include/asm-i386/string.h Tue Apr 17 14:43:34 2001 @@ -446,34 +446,8 @@ /* end of additional stuff */ #define __HAVE_ARCH_STRSTR -static inline 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; -} + +extern char *strstr(const char *cs, const char *ct); /* * This looks horribly ugly, but the compiler can optimize it totally, diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/a.out.h linux/include/asm-ia64/a.out.h --- v2.4.3/linux/include/asm-ia64/a.out.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/a.out.h Thu Apr 5 12:51:47 2001 @@ -30,7 +30,8 @@ #define N_TXTOFF(x) 0 #ifdef __KERNEL__ -# define STACK_TOP (0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12))) +# include <asm/page.h> +# define STACK_TOP (0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) # define IA64_RBS_BOT (STACK_TOP - 0x80000000L) /* bottom of register backing store */ #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/acpikcfg.h linux/include/asm-ia64/acpikcfg.h --- v2.4.3/linux/include/asm-ia64/acpikcfg.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/acpikcfg.h Thu Apr 5 12:51:47 2001 @@ -1,4 +1,5 @@ #include <linux/config.h> + #ifdef CONFIG_ACPI_KERNEL_CONFIG /* * acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/asmmacro.h linux/include/asm-ia64/asmmacro.h --- v2.4.3/linux/include/asm-ia64/asmmacro.h Fri Aug 11 19:09:06 2000 +++ linux/include/asm-ia64/asmmacro.h Thu Apr 5 12:51:47 2001 @@ -2,26 +2,10 @@ #define _ASM_IA64_ASMMACRO_H /* - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Copyright (C) 2000-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ -#if 1 - -/* - * This is a hack that's necessary as long as we support old versions - * of gas, that have no unwind support. - */ -#include <linux/config.h> - -#ifdef CONFIG_IA64_NEW_UNWIND -# define UNW(args...) args -#else -# define UNW(args...) -#endif - -#endif - #define ENTRY(name) \ .align 32; \ .proc name; \ @@ -44,5 +28,28 @@ #define ASM_UNW_PRLG_PSP 0x2 #define ASM_UNW_PRLG_PR 0x1 #define ASM_UNW_PRLG_GRSAVE(ninputs) (32+(ninputs)) + +/* + * Helper macros for accessing user memory. + */ + + .section "__ex_table", "a" // declare section & section attributes + .previous + +#if __GNUC__ >= 3 +# define EX(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y); \ + [99:] x +# define EXCLR(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y)+4; \ + [99:] x +#else +# define EX(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y); \ + 99: x +# define EXCLR(y,x...) \ + .xdata4 "__ex_table", @gprel(99f), @gprel(y)+4; \ + 99: x +#endif #endif /* _ASM_IA64_ASMMACRO_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/bitops.h linux/include/asm-ia64/bitops.h --- v2.4.3/linux/include/asm-ia64/bitops.h Mon Oct 9 17:54:57 2000 +++ linux/include/asm-ia64/bitops.h Thu Apr 5 12:51:47 2001 @@ -158,6 +158,7 @@ __asm__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d)); return exp - 0xffff; } + /* * ffs: find first bit set. This is defined the same way as * the libc and compiler builtin ffs routines, therefore diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/byteorder.h linux/include/asm-ia64/byteorder.h --- v2.4.3/linux/include/asm-ia64/byteorder.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/byteorder.h Thu Apr 5 12:51:47 2001 @@ -20,18 +20,18 @@ static __inline__ __const__ __u32 __ia64_swab32 (__u32 x) { - return __ia64_swab64 (x) >> 32; + return __ia64_swab64(x) >> 32; } static __inline__ __const__ __u16 __ia64_swab16(__u16 x) { - return __ia64_swab64 (x) >> 48; + return __ia64_swab64(x) >> 48; } -#define __arch__swab64(x) __ia64_swab64 (x) -#define __arch__swab32(x) __ia64_swab32 (x) -#define __arch__swab16(x) __ia64_swab16 (x) +#define __arch__swab64(x) __ia64_swab64(x) +#define __arch__swab32(x) __ia64_swab32(x) +#define __arch__swab16(x) __ia64_swab16(x) #define __BYTEORDER_HAS_U64__ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/cache.h linux/include/asm-ia64/cache.h --- v2.4.3/linux/include/asm-ia64/cache.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/cache.h Thu Apr 5 12:51:47 2001 @@ -9,7 +9,7 @@ */ /* Bytes per L1 (data) cache line. */ -#define L1_CACHE_SHIFT 6 +#define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/delay.h linux/include/asm-ia64/delay.h --- v2.4.3/linux/include/asm-ia64/delay.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/delay.h Thu Apr 5 12:51:47 2001 @@ -34,13 +34,9 @@ } static __inline__ void -ia64_set_itv (unsigned char vector, unsigned char masked) +ia64_set_itv (unsigned long val) { - if (masked > 1) - masked = 1; - - __asm__ __volatile__("mov cr.itv=%0;; srlz.d;;" - :: "r"((masked << 16) | vector) : "memory"); + __asm__ __volatile__("mov cr.itv=%0;; srlz.d;;" :: "r"(val) : "memory"); } static __inline__ void @@ -79,16 +75,11 @@ static __inline__ void udelay (unsigned long usecs) { -#ifdef CONFIG_IA64_SOFTSDV_HACKS - while (usecs--) - ; -#else unsigned long start = ia64_get_itc(); - unsigned long cycles = usecs*my_cpu_data.cyc_per_usec; + unsigned long cycles = usecs*local_cpu_data->cyc_per_usec; while (ia64_get_itc() - start < cycles) /* skip */; -#endif /* CONFIG_IA64_SOFTSDV_HACKS */ } #endif /* _ASM_IA64_DELAY_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/dma.h linux/include/asm-ia64/dma.h --- v2.4.3/linux/include/asm-ia64/dma.h Thu Jun 22 07:09:45 2000 +++ linux/include/asm-ia64/dma.h Thu Apr 5 12:51:47 2001 @@ -2,35 +2,20 @@ #define _ASM_IA64_DMA_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> -#include <linux/spinlock.h> /* And spinlocks */ -#include <linux/delay.h> #include <asm/io.h> /* need byte IO */ -#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER -#define dma_outb outb_p -#else -#define dma_outb outb -#endif - -#define dma_inb inb - -#define MAX_DMA_CHANNELS 8 -#define MAX_DMA_ADDRESS 0xffffffffUL - -extern spinlock_t dma_spin_lock; - -/* From PCI */ +extern unsigned long MAX_DMA_ADDRESS; #ifdef CONFIG_PCI -extern int isa_dma_bridge_buggy; + extern int isa_dma_bridge_buggy; #else -#define isa_dma_bridge_buggy (0) +# define isa_dma_bridge_buggy (0) #endif #endif /* _ASM_IA64_DMA_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/efi.h linux/include/asm-ia64/efi.h --- v2.4.3/linux/include/asm-ia64/efi.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/efi.h Thu Apr 5 12:51:47 2001 @@ -4,7 +4,7 @@ /* * Extensible Firmware Interface * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 - * + * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Hewlett-Packard Co. @@ -20,9 +20,12 @@ #include <asm/system.h> #define EFI_SUCCESS 0 -#define EFI_INVALID_PARAMETER 2 -#define EFI_UNSUPPORTED 3 -#define EFI_BUFFER_TOO_SMALL 4 +#define EFI_LOAD_ERROR (1L | (1L << 63)) +#define EFI_INVALID_PARAMETER (2L | (1L << 63)) +#define EFI_UNSUPPORTED (3L | (1L << 63)) +#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) +#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) +#define EFI_NOT_FOUND (14L | (1L << 63)) typedef unsigned long efi_status_t; typedef u8 efi_bool_t; @@ -173,7 +176,7 @@ #define SMBIOS_TABLE_GUID \ ((efi_guid_t) { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) - + #define SAL_SYSTEM_TABLE_GUID \ ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) @@ -183,7 +186,7 @@ } efi_config_table_t; #define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 -#define EFI_SYSTEM_TABLE_REVISION ((0 << 16) | (92)) +#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00) typedef struct { efi_table_hdr_t hdr; @@ -234,5 +237,13 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); extern void efi_gettimeofday (struct timeval *tv); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ + + +/* + * Variable Attributes + */ +#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 #endif /* _ASM_IA64_EFI_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/hardirq.h linux/include/asm-ia64/hardirq.h --- v2.4.3/linux/include/asm-ia64/hardirq.h Sun Dec 3 17:45:23 2000 +++ linux/include/asm-ia64/hardirq.h Thu Apr 5 12:51:47 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_HARDIRQ_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> @@ -11,36 +11,38 @@ #include <linux/threads.h> #include <linux/irq.h> -/* entry.S is sensitive to the offsets of these fields */ -typedef struct { - unsigned int __softirq_active; - unsigned int __softirq_mask; - unsigned int __local_irq_count; - unsigned int __local_bh_count; - unsigned int __syscall_count; - unsigned int __nmi_count; /* arch dependent */ -} ____cacheline_aligned irq_cpustat_t; - -#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ +#include <asm/processor.h> /* - * Are we in an interrupt context? Either doing bottom half - * or hardware interrupt processing? + * No irq_cpustat_t for IA-64. The data is held in the per-CPU data structure. */ -#define in_interrupt() \ -({ \ - int __cpu = smp_processor_id(); \ - (local_irq_count(__cpu) + local_bh_count(__cpu)) != 0; \ -}) +#define softirq_active(cpu) (cpu_data[cpu].softirq.active) +#define softirq_mask(cpu) (cpu_data[cpu].softirq.mask) +#define irq_count(cpu) (cpu_data[cpu].irq_stat.f.irq_count) +#define bh_count(cpu) (cpu_data[cpu].irq_stat.f.bh_count) +#define syscall_count(cpu) /* unused on IA-64 */ +#define nmi_count(cpu) 0 + +#define local_softirq_active() (local_cpu_data->softirq.active) +#define local_softirq_mask() (local_cpu_data->softirq.mask) +#define local_irq_count() (local_cpu_data->irq_stat.f.irq_count) +#define local_bh_count() (local_cpu_data->irq_stat.f.bh_count) +#define local_syscall_count() /* unused on IA-64 */ +#define local_nmi_count() 0 -#define in_irq() (local_irq_count(smp_processor_id()) != 0) +/* + * Are we in an interrupt context? Either doing bottom half or hardware interrupt + * processing? + */ +#define in_interrupt() (local_cpu_data->irq_stat.irq_and_bh_counts != 0) +#define in_irq() (local_cpu_data->irq_stat.f.irq_count != 0) #ifndef CONFIG_SMP -# define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -# define hardirq_endlock(cpu) do { } while (0) +# define local_hardirq_trylock() (local_irq_count() == 0) +# define local_hardirq_endlock() do { } while (0) -# define irq_enter(cpu, irq) (local_irq_count(cpu)++) -# define irq_exit(cpu, irq) (local_irq_count(cpu)--) +# define local_irq_enter(irq) (local_irq_count()++) +# define local_irq_exit(irq) (local_irq_count()--) # define synchronize_irq() barrier() #else @@ -51,17 +53,19 @@ extern unsigned int global_irq_holder; extern volatile unsigned long global_irq_lock; -static inline int irqs_running (void) +static inline int +irqs_running (void) { int i; for (i = 0; i < smp_num_cpus; i++) - if (local_irq_count(i)) + if (irq_count(i)) return 1; return 0; } -static inline void release_irqlock(int cpu) +static inline void +release_irqlock (int cpu) { /* if we didn't own the irq lock, just ignore.. */ if (global_irq_holder == cpu) { @@ -70,28 +74,31 @@ } } -static inline void irq_enter(int cpu, int irq) +static inline void +local_irq_enter (int irq) { - local_irq_count(cpu)++; + local_irq_count()++; while (test_bit(0,&global_irq_lock)) { /* nothing */; } } -static inline void irq_exit(int cpu, int irq) +static inline void +local_irq_exit (int irq) { - local_irq_count(cpu)--; + local_irq_count()--; } -static inline int hardirq_trylock(int cpu) +static inline int +local_hardirq_trylock (void) { - return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock); + return !local_irq_count() && !test_bit(0,&global_irq_lock); } -#define hardirq_endlock(cpu) do { } while (0) +#define local_hardirq_endlock() do { } while (0) -extern void synchronize_irq(void); +extern void synchronize_irq (void); #endif /* CONFIG_SMP */ #endif /* _ASM_IA64_HARDIRQ_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/hw_irq.h linux/include/asm-ia64/hw_irq.h --- v2.4.3/linux/include/asm-ia64/hw_irq.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/hw_irq.h Thu Apr 5 12:51:47 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_HW_IRQ_H /* - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/sched.h> @@ -13,6 +13,8 @@ #include <asm/ptrace.h> #include <asm/smp.h> +typedef u8 ia64_vector; + /* * 0 special * @@ -26,31 +28,32 @@ * * 15 classes of 16 interrupts each. */ -#define IA64_MIN_VECTORED_IRQ 16 -#define IA64_MAX_VECTORED_IRQ 255 +#define IA64_MIN_VECTORED_IRQ 16 +#define IA64_MAX_VECTORED_IRQ 255 +#define IA64_NUM_VECTORS 256 -#define IA64_SPURIOUS_INT 0x0f +#define IA64_SPURIOUS_INT_VECTOR 0x0f /* * Vectors 0x10-0x1f are used for low priority interrupts, e.g. CMCI. */ -#define PCE_IRQ 0x1e /* platform corrected error interrupt vector */ -#define CMC_IRQ 0x1f /* correctable machine-check interrupt vector */ +#define IA64_PCE_VECTOR 0x1e /* platform corrected error interrupt vector */ +#define IA64_CMC_VECTOR 0x1f /* correctable machine-check interrupt vector */ /* * Vectors 0x20-0x2f are reserved for legacy ISA IRQs. */ -#define FIRST_DEVICE_IRQ 0x30 -#define LAST_DEVICE_IRQ 0xe7 +#define IA64_FIRST_DEVICE_VECTOR 0x30 +#define IA64_LAST_DEVICE_VECTOR 0xe7 -#define MCA_RENDEZ_IRQ 0xe8 /* MCA rendez interrupt */ -#define PERFMON_IRQ 0xee /* performanc monitor interrupt vector */ -#define TIMER_IRQ 0xef /* use highest-prio group 15 interrupt for timer */ -#define MCA_WAKEUP_IRQ 0xf0 /* MCA wakeup interrupt (must be higher than MCA_RENDEZ_IRQ) */ -#define IPI_IRQ 0xfe /* inter-processor interrupt vector */ +#define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ +#define IA64_PERFMON_VECTOR 0xee /* performanc monitor interrupt vector */ +#define IA64_TIMER_VECTOR 0xef /* use highest-prio group 15 interrupt for timer */ +#define IA64_MCA_WAKEUP_VECTOR 0xf0 /* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */ +#define IA64_IPI_VECTOR 0xfe /* inter-processor interrupt vector */ /* IA64 inter-cpu interrupt related definitions */ -#define IPI_DEFAULT_BASE_ADDR 0xfee00000 +#define IA64_IPI_DEFAULT_BASE_ADDR 0xfee00000 /* Delivery modes for inter-cpu interrupts */ enum { @@ -61,9 +64,6 @@ IA64_IPI_DM_EXTINT = 0x7, /* pend an 8259-compatible interrupt. */ }; -#define IA64_BUS_ID(cpu) (cpu >> 8) -#define IA64_LOCAL_ID(cpu) (cpu & 0xff) - extern __u8 isa_irq_to_vector_map[16]; #define isa_irq_to_vector(x) isa_irq_to_vector_map[(x)] @@ -73,11 +73,71 @@ extern int ia64_alloc_irq (void); /* allocate a free irq */ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); +extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); static inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int vector) { platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); +} + +/* + * Default implementations for the irq-descriptor API: + */ + +extern struct irq_desc _irq_desc[NR_IRQS]; + +static inline struct irq_desc * +__ia64_irq_desc (unsigned int irq) +{ + return _irq_desc + irq; +} + +static inline ia64_vector +__ia64_irq_to_vector (unsigned int irq) +{ + return (ia64_vector) irq; +} + +static inline unsigned int +__ia64_local_vector_to_irq (ia64_vector vec) +{ + return (unsigned int) vec; +} + +/* + * Next follows the irq descriptor interface. On IA-64, each CPU supports 256 interrupt + * vectors. On smaller systems, there is a one-to-one correspondence between interrupt + * vectors and the Linux irq numbers. However, larger systems may have multiple interrupt + * domains meaning that the translation from vector number to irq number depends on the + * interrupt domain that a CPU belongs to. This API abstracts such platform-dependent + * differences and provides a uniform means to translate between vector and irq numbers + * and to obtain the irq descriptor for a given irq number. + */ + +/* Return a pointer to the irq descriptor for IRQ. */ +static inline struct irq_desc * +irq_desc (int irq) +{ + return platform_irq_desc(irq); +} + +/* Extract the IA-64 vector that corresponds to IRQ. */ +static inline ia64_vector +irq_to_vector (int irq) +{ + return platform_irq_to_vector(irq); +} + +/* + * Convert the local IA-64 vector to the corresponding irq number. This translation is + * done in the context of the interrupt domain that the currently executing CPU belongs + * to. + */ +static inline unsigned int +local_vector_to_irq (ia64_vector vec) +{ + return platform_local_vector_to_irq(vec); } #endif /* _ASM_IA64_HW_IRQ_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/ia32.h linux/include/asm-ia64/ia32.h --- v2.4.3/linux/include/asm-ia64/ia32.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/ia32.h Fri Apr 13 20:26:07 2001 @@ -355,7 +355,7 @@ (granularity << IA32_SEG_G) | \ (((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE)) -#define IA32_IOBASE 0x2000000000000000 /* Virtual addres for I/O space */ +#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ #define IA32_CR0 0x80000001 /* Enable PG and PE bits */ #define IA32_CR4 0 /* No architectural extensions */ @@ -378,9 +378,10 @@ ia64_psr(regs)->ri = 0; /* clear return slot number */ \ ia64_psr(regs)->is = 1; /* IA-32 instruction set */ \ regs->cr_iip = new_ip; \ - regs->r12 = new_sp; \ + regs->ar_rsc = 0xc; /* enforced lazy mode, priv. level 3 */ \ regs->ar_rnat = 0; \ regs->loadrs = 0; \ + regs->r12 = new_sp; \ } while (0) extern void ia32_gdt_init (void); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/io.h linux/include/asm-ia64/io.h --- v2.4.3/linux/include/asm-ia64/io.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/io.h Thu Apr 5 12:51:47 2001 @@ -13,8 +13,8 @@ * over and over again with slight variations and possibly making a * mistake somewhere. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> */ @@ -82,21 +82,11 @@ } /* - * For the in/out instructions, we need to do: - * - * o "mf" _before_ doing the I/O access to ensure that all prior - * accesses to memory occur before the I/O access - * o "mf.a" _after_ doing the I/O access to ensure that the access - * has completed before we're doing any other I/O accesses - * - * The former is necessary because we might be doing normal (cached) memory - * accesses, e.g., to set up a DMA descriptor table and then do an "outX()" - * to tell the DMA controller to start the DMA operation. The "mf" ahead - * of the I/O operation ensures that the DMA table is correct when the I/O - * access occurs. - * - * The mf.a is necessary to ensure that all I/O access occur in program - * order. --davidm 99/12/07 + * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure + * that the access has completed before executing other I/O accesses. Since we're doing + * the accesses through an uncachable (UC) translation, the CPU will execute them in + * program order. However, we still need to tell the compiler not to shuffle them around + * during optimization, which is why we use "volatile" pointers. */ static inline unsigned int @@ -378,17 +368,16 @@ #endif /* - * An "address" in IO memory space is not clearly either an integer - * or a pointer. We will accept both, thus the casts. + * An "address" in IO memory space is not clearly either an integer or a pointer. We will + * accept both, thus the casts. * - * On ia-64, we access the physical I/O memory space through the - * uncached kernel region. + * On ia-64, we access the physical I/O memory space through the uncached kernel region. */ static inline void * ioremap (unsigned long offset, unsigned long size) { return (void *) (__IA64_UNCACHED_OFFSET | (offset)); -} +} static inline void iounmap (void *addr) @@ -412,75 +401,6 @@ __ia64_memcpy_toio((unsigned long)(to),(from),(len)) #define memset_io(addr,c,len) \ __ia64_memset_c_io((unsigned long)(addr),0x0101010101010101UL*(u8)(c),(len)) - -#define __HAVE_ARCH_MEMSETW_IO -#define memsetw_io(addr,c,len) \ - _memset_c_io((unsigned long)(addr),0x0001000100010001UL*(u16)(c),(len)) - -/* - * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and - * just copy it. The net code will then do the checksum later. Presently - * only used by some shared memory 8390 Ethernet cards anyway. - */ - -#define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len)) - -#if 0 - -/* - * XXX this is the kind of legacy stuff we want to get rid of with IA-64... --davidm 99/12/02 - */ - -/* - * This is used for checking BIOS signatures. It's not clear at all - * why this is here. This implementation seems to be the same on - * all architectures. Strange. - */ -static inline int -check_signature (unsigned long io_addr, const unsigned char *signature, int length) -{ - int retval = 0; - do { - if (readb(io_addr) != *signature) - goto out; - io_addr++; - signature++; - length--; - } while (length); - retval = 1; -out: - return retval; -} - -#define RTC_PORT(x) (0x70 + (x)) -#define RTC_ALWAYS_BCD 0 - -#endif - -/* - * The caches on some architectures aren't DMA-coherent and have need - * to handle this in software. There are two types of operations that - * can be applied to dma buffers. - * - * - dma_cache_inv(start, size) invalidates the affected parts of the - * caches. Dirty lines of the caches may be written back or simply - * be discarded. This operation is necessary before dma operations - * to the memory. - * - * - dma_cache_wback(start, size) makes caches and memory coherent - * by writing the content of the caches back to memory, if necessary - * (cache flush). - * - * - dma_cache_wback_inv(start, size) Like dma_cache_wback() but the - * function also invalidates the affected part of the caches as - * necessary before DMA transfers from outside to memory. - * - * Fortunately, the IA-64 architecture mandates cache-coherent DMA, so - * these functions can be implemented as no-ops. - */ -#define dma_cache_inv(_start,_size) do { } while (0) -#define dma_cache_wback(_start,_size) do { } while (0) -#define dma_cache_wback_inv(_start,_size) do { } while (0) # endif /* __KERNEL__ */ #endif /* _ASM_IA64_IO_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/kregs.h linux/include/asm-ia64/kregs.h --- v2.4.3/linux/include/asm-ia64/kregs.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ia64/kregs.h Thu Apr 5 12:51:47 2001 @@ -0,0 +1,33 @@ +#ifndef _ASM_IA64_KREGS_H +#define _ASM_IA64_KREGS_H + +/* + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + */ +/* + * This file defines the kernel register usage convention used by Linux/ia64. + */ + +/* + * Kernel registers: + */ +#define IA64_KR_IO_BASE 0 /* ar.k0: legacy I/O base address */ +#define IA64_KR_CURRENT_STACK 4 /* ar.k4: what's mapped in IA64_TR_CURRENT_STACK */ +#define IA64_KR_FPU_OWNER 5 /* ar.k5: fpu-owner (UP only, at the moment) */ +#define IA64_KR_CURRENT 6 /* ar.k6: "current" task pointer */ +#define IA64_KR_PT_BASE 7 /* ar.k7: page table base address (physical) */ + +#define _IA64_KR_PASTE(x,y) x##y +#define _IA64_KR_PREFIX(n) _IA64_KR_PASTE(ar.k, n) +#define IA64_KR(n) _IA64_KR_PREFIX(IA64_KR_##n) + +/* + * Translation registers: + */ +#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */ +#define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ +#define IA64_TR_PERCPU_DATA 1 /* dtr1: percpu data */ +#define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel memory & register stacks */ + +#endif /* _ASM_IA64_kREGS_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/machvec.h linux/include/asm-ia64/machvec.h --- v2.4.3/linux/include/asm-ia64/machvec.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/machvec.h Thu Apr 5 12:51:47 2001 @@ -4,8 +4,8 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com> * Copyright (C) Vijay Chander <vijay@engr.sgi.com> - * Copyright (C) 1999-2000 Hewlett-Packard Co. - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co. + * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #ifndef _ASM_IA64_MACHVEC_H #define _ASM_IA64_MACHVEC_H @@ -17,6 +17,7 @@ struct pci_dev; struct pt_regs; struct scatterlist; +struct irq_desc; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_irq_init_t (void); @@ -27,6 +28,9 @@ typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *); typedef void ia64_mv_log_print_t (void); typedef void ia64_mv_send_ipi_t (int, int, int, int); +typedef struct irq_desc *ia64_mv_irq_desc (unsigned int); +typedef u8 ia64_mv_irq_to_vector (u8); +typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector); /* PCI-DMA interface: */ typedef void ia64_mv_pci_dma_init (void); @@ -88,6 +92,9 @@ # define platform_pci_dma_sync_single ia64_mv.sync_single # define platform_pci_dma_sync_sg ia64_mv.sync_sg # define platform_pci_dma_address ia64_mv.dma_address +# define platform_irq_desc ia64_mv.irq_desc +# define platform_irq_to_vector ia64_mv.irq_to_vector +# define platform_local_vector_to_irq ia64_mv.local_vector_to_irq # define platform_inb ia64_mv.inb # define platform_inw ia64_mv.inw # define platform_inl ia64_mv.inl @@ -117,6 +124,9 @@ ia64_mv_pci_dma_sync_single *sync_single; ia64_mv_pci_dma_sync_sg *sync_sg; ia64_mv_pci_dma_address *dma_address; + ia64_mv_irq_desc *irq_desc; + ia64_mv_irq_to_vector *irq_to_vector; + ia64_mv_local_vector_to_irq *local_vector_to_irq; ia64_mv_inb_t *inb; ia64_mv_inw_t *inw; ia64_mv_inl_t *inl; @@ -147,6 +157,9 @@ platform_pci_dma_sync_single, \ platform_pci_dma_sync_sg, \ platform_pci_dma_address, \ + platform_irq_desc, \ + platform_irq_to_vector, \ + platform_local_vector_to_irq, \ platform_inb, \ platform_inw, \ platform_inl, \ @@ -233,6 +246,15 @@ #endif #ifndef platform_pci_dma_address # define platform_pci_dma_address swiotlb_dma_address +#endif +#ifndef platform_irq_desc +# define platform_irq_desc __ia64_irq_desc +#endif +#ifndef platform_irq_to_vector +# define platform_irq_to_vector __ia64_irq_to_vector +#endif +#ifndef platform_local_vector_to_irq +# define platform_local_vector_to_irq __ia64_local_vector_to_irq #endif #ifndef platform_inb # define platform_inb __ia64_inb diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/machvec_sn1.h linux/include/asm-ia64/machvec_sn1.h --- v2.4.3/linux/include/asm-ia64/machvec_sn1.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/machvec_sn1.h Thu Apr 5 12:51:47 2001 @@ -41,6 +41,7 @@ #define platform_outb sn1_outb #define platform_outw sn1_outw #define platform_outl sn1_outl +#define platform_pci_dma_init machvec_noop #define platform_pci_alloc_consistent sn1_pci_alloc_consistent #define platform_pci_free_consistent sn1_pci_free_consistent #define platform_pci_map_single sn1_pci_map_single diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/mca.h linux/include/asm-ia64/mca.h --- v2.4.3/linux/include/asm-ia64/mca.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/mca.h Thu Apr 5 12:51:47 2001 @@ -1,6 +1,6 @@ /* - * File: mca.h - * Purpose: Machine check handling specific defines + * File: mca.h + * Purpose: Machine check handling specific defines * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander (vijay@engr.sgi.com) @@ -18,7 +18,6 @@ #include <asm/param.h> #include <asm/sal.h> #include <asm/processor.h> -#include <asm/hw_irq.h> /* These are the return codes from all the IA64_MCA specific interfaces */ typedef int ia64_mca_return_code_t; @@ -30,11 +29,6 @@ #define IA64_MCA_RENDEZ_TIMEOUT (100 * HZ) /* 1000 milliseconds */ -/* Interrupt vectors reserved for MC handling. */ -#define IA64_MCA_RENDEZ_INT_VECTOR MCA_RENDEZ_IRQ /* Rendez interrupt */ -#define IA64_MCA_WAKEUP_INT_VECTOR MCA_WAKEUP_IRQ /* Wakeup interrupt */ -#define IA64_MCA_CMC_INT_VECTOR CMC_IRQ /* Correctable machine check interrupt */ - #define IA64_CMC_INT_DISABLE 0 #define IA64_CMC_INT_ENABLE 1 @@ -45,7 +39,7 @@ typedef union cmcv_reg_u { u64 cmcv_regval; struct { - u64 cmcr_vector : 8; + u64 cmcr_vector : 8; u64 cmcr_reserved1 : 4; u64 cmcr_ignored1 : 1; u64 cmcr_reserved2 : 3; @@ -63,15 +57,15 @@ #define IA64_INIT_HANDLER_SIZE 0x10 enum { - IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, - IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 + IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, + IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 }; #define IA64_MAXCPUS 64 /* Need to do something about this */ /* Information maintained by the MC infrastructure */ typedef struct ia64_mc_info_s { - u64 imi_mca_handler; + u64 imi_mca_handler; size_t imi_mca_handler_size; u64 imi_monarch_init_handler; size_t imi_monarch_init_handler_size; @@ -85,7 +79,7 @@ * handoff */ enum { - IA64_MCA_RENDEZ_NOT_RQD = 0x0, + IA64_MCA_RENDEZ_NOT_RQD = 0x0, IA64_MCA_RENDEZ_DONE_WITHOUT_INIT = 0x1, IA64_MCA_RENDEZ_DONE_WITH_INIT = 0x2, IA64_MCA_RENDEZ_FAILURE = -1 @@ -103,12 +97,12 @@ } ia64_mca_sal_to_os_state_t; enum { - IA64_MCA_CORRECTED = 0x0, /* Error has been corrected by OS_MCA */ + IA64_MCA_CORRECTED = 0x0, /* Error has been corrected by OS_MCA */ IA64_MCA_WARM_BOOT = -1, /* Warm boot of the system need from SAL */ IA64_MCA_COLD_BOOT = -2, /* Cold boot of the system need from SAL */ IA64_MCA_HALT = -3 /* System to be halted by SAL */ }; - + typedef struct ia64_mca_os_to_sal_state_s { u64 imots_os_status; /* OS status to SAL as to what happened * with the MCA handling. @@ -138,7 +132,7 @@ #define PLATFORM_CALL(fn, args) printk("Platform call TBD\n") -#undef MCA_TEST +#undef MCA_TEST #define IA64_MCA_DEBUG_INFO 1 diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/mca_asm.h linux/include/asm-ia64/mca_asm.h --- v2.4.3/linux/include/asm-ia64/mca_asm.h Fri Apr 21 15:21:24 2000 +++ linux/include/asm-ia64/mca_asm.h Thu Apr 5 12:51:47 2001 @@ -72,7 +72,7 @@ ;; \ dep old_psr = 0, old_psr, 32, 32; \ \ - mov ar.rsc = r0 ; \ + mov ar.rsc = 0 ; \ ;; \ mov temp2 = ar.bspstore; \ ;; \ @@ -148,7 +148,7 @@ dep temp2 = 0, temp2, PSR_IC, 2; \ ;; \ mov psr.l = temp2; \ - mov ar.rsc = r0; \ + mov ar.rsc = 0; \ ;; \ srlz.d; \ mov temp2 = ar.bspstore; \ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/mmu_context.h linux/include/asm-ia64/mmu_context.h --- v2.4.3/linux/include/asm-ia64/mmu_context.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/mmu_context.h Thu Apr 5 12:51:47 2001 @@ -2,35 +2,32 @@ #define _ASM_IA64_MMU_CONTEXT_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ -#include <linux/sched.h> -#include <linux/spinlock.h> - -#include <asm/processor.h> - /* - * Routines to manage the allocation of task context numbers. Task - * context numbers are used to reduce or eliminate the need to perform - * TLB flushes due to context switches. Context numbers are - * implemented using ia-64 region ids. Since ia-64 TLBs do not - * guarantee that the region number is checked when performing a TLB - * lookup, we need to assign a unique region id to each region in a - * process. We use the least significant three bits in a region id - * for this purpose. On processors where the region number is checked - * in TLB lookups, we can get back those two bits by defining - * CONFIG_IA64_TLB_CHECKS_REGION_NUMBER. The macro - * IA64_REGION_ID_BITS gives the number of bits in a region id. The - * architecture manual guarantees this number to be in the range - * 18-24. + * Routines to manage the allocation of task context numbers. Task context numbers are + * used to reduce or eliminate the need to perform TLB flushes due to context switches. + * Context numbers are implemented using ia-64 region ids. Since the IA-64 TLB does not + * consider the region number when performing a TLB lookup, we need to assign a unique + * region id to each region in a process. We use the least significant three bits in a + * region id for this purpose. * - * Copyright (C) 1998 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #define IA64_REGION_ID_KERNEL 0 /* the kernel's region id (tlb.c depends on this being 0) */ +#define ia64_rid(ctx,addr) (((ctx) << 3) | (addr >> 61)) + +# ifndef __ASSEMBLY__ + +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/processor.h> + struct ia64_ctx { spinlock_t lock; unsigned int next; /* next context number to use */ @@ -47,12 +44,6 @@ { } -static inline unsigned long -ia64_rid (unsigned long context, unsigned long region_addr) -{ - return context << 3 | (region_addr >> 61); -} - static inline void get_new_mmu_context (struct mm_struct *mm) { @@ -123,11 +114,12 @@ * We may get interrupts here, but that's OK because interrupt * handlers cannot touch user-space. */ - __asm__ __volatile__ ("mov ar.k7=%0" :: "r"(__pa(next->pgd))); + ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd)); get_mmu_context(next); reload_context(next); } #define switch_mm(prev_mm,next_mm,next_task,cpu) activate_mm(prev_mm, next_mm) +# endif /* ! __ASSEMBLY__ */ #endif /* _ASM_IA64_MMU_CONTEXT_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/module.h linux/include/asm-ia64/module.h --- v2.4.3/linux/include/asm-ia64/module.h Thu Jan 4 12:50:17 2001 +++ linux/include/asm-ia64/module.h Thu Apr 12 12:16:36 2001 @@ -7,7 +7,6 @@ * Copyright (C) 2000 Mike Stephens <mike.stephens@intel.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/vmalloc.h> #include <asm/unwind.h> @@ -35,7 +34,6 @@ static inline int ia64_module_init(struct module *mod) { -#ifdef CONFIG_IA64_NEW_UNWIND struct archdata *archdata; if (!mod_member_present(mod, archdata_start) || !mod->archdata_start) @@ -79,14 +77,12 @@ (unsigned long) archdata->segment_base, (unsigned long) archdata->gp, archdata->unw_start, archdata->unw_end); -#endif /* CONFIG_IA64_NEW_UNWIND */ return 0; } static inline void ia64_module_unmap(void * addr) { -#ifdef CONFIG_IA64_NEW_UNWIND struct module *mod = (struct module *) addr; struct archdata *archdata; @@ -100,7 +96,6 @@ if (archdata->unw_table != NULL) unw_remove_unwind_table((void *) archdata->unw_table); } -#endif /* CONFIG_IA64_NEW_UNWIND */ vfree(addr); } diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h --- v2.4.3/linux/include/asm-ia64/offsets.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/offsets.h Thu Apr 5 12:51:47 2001 @@ -11,10 +11,11 @@ #define PT_PTRACED_BIT 0 #define PT_TRACESYS_BIT 1 -#define IA64_TASK_SIZE 3376 /* 0xd30 */ +#define IA64_TASK_SIZE 3904 /* 0xf40 */ #define IA64_PT_REGS_SIZE 400 /* 0x190 */ #define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */ #define IA64_SIGINFO_SIZE 128 /* 0x80 */ +#define IA64_CPU_SIZE 16384 /* 0x4000 */ #define UNW_FRAME_INFO_SIZE 448 /* 0x1c0 */ #define IA64_TASK_PTRACE_OFFSET 48 /* 0x30 */ @@ -23,7 +24,8 @@ #define IA64_TASK_PROCESSOR_OFFSET 100 /* 0x64 */ #define IA64_TASK_THREAD_OFFSET 1456 /* 0x5b0 */ #define IA64_TASK_THREAD_KSP_OFFSET 1456 /* 0x5b0 */ -#define IA64_TASK_THREAD_SIGMASK_OFFSET 3224 /* 0xc98 */ +#define IA64_TASK_THREAD_SIGMASK_OFFSET 3752 /* 0xea8 */ +#define IA64_TASK_PFM_NOTIFY_OFFSET 3648 /* 0xe40 */ #define IA64_TASK_PID_OFFSET 196 /* 0xc4 */ #define IA64_TASK_MM_OFFSET 88 /* 0x58 */ #define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */ @@ -123,5 +125,10 @@ #define IA64_SIGCONTEXT_FR6_OFFSET 560 /* 0x230 */ #define IA64_CLONE_VFORK 16384 /* 0x4000 */ #define IA64_CLONE_VM 256 /* 0x100 */ +#define IA64_CPU_IRQ_COUNT_OFFSET 8 /* 0x8 */ +#define IA64_CPU_BH_COUNT_OFFSET 12 /* 0xc */ +#define IA64_CPU_SOFTIRQ_ACTIVE_OFFSET 0 /* 0x0 */ +#define IA64_CPU_SOFTIRQ_MASK_OFFSET 4 /* 0x4 */ +#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 16 /* 0x10 */ #endif /* _ASM_IA64_OFFSETS_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/page.h linux/include/asm-ia64/page.h --- v2.4.3/linux/include/asm-ia64/page.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/page.h Thu Apr 5 12:51:47 2001 @@ -40,43 +40,6 @@ extern void clear_page (void *page); extern void copy_page (void *to, void *from); -# ifdef STRICT_MM_TYPECHECKS -/* - * These are used to make use of C type-checking.. - */ -typedef struct { unsigned long pte; } pte_t; -typedef struct { unsigned long pmd; } pmd_t; -typedef struct { unsigned long pgd; } pgd_t; -typedef struct { unsigned long pgprot; } pgprot_t; - -#define pte_val(x) ((x).pte) -#define pmd_val(x) ((x).pmd) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) - -#define __pte(x) ((pte_t) { (x) } ) -#define __pgprot(x) ((pgprot_t) { (x) } ) - -# else /* !STRICT_MM_TYPECHECKS */ -/* - * .. while these make it easier on the compiler - */ -typedef unsigned long pte_t; -typedef unsigned long pmd_t; -typedef unsigned long pgd_t; -typedef unsigned long pgprot_t; - -#define pte_val(x) (x) -#define pmd_val(x) (x) -#define pgd_val(x) (x) -#define pgprot_val(x) (x) - -#define __pte(x) (x) -#define __pgd(x) (x) -#define __pgprot(x) (x) - -# endif /* !STRICT_MM_TYPECHECKS */ - /* * Note: the MAP_NR_*() macro can't use __pa() because MAP_NR_*(X) MUST * map to something >= max_mapnr if X is outside the identity mapped @@ -133,7 +96,7 @@ { double d = size - 1; long order; - + __asm__ ("getf.exp %0=%1" : "=r"(order) : "f"(d)); order = order - PAGE_SHIFT - 0xffff + 1; if (order < 0) @@ -142,7 +105,45 @@ } # endif /* __KERNEL__ */ -#endif /* !ASSEMBLY */ +#endif /* !__ASSEMBLY__ */ + +#ifdef STRICT_MM_TYPECHECKS + /* + * These are used to make use of C type-checking.. + */ + typedef struct { unsigned long pte; } pte_t; + typedef struct { unsigned long pmd; } pmd_t; + typedef struct { unsigned long pgd; } pgd_t; + typedef struct { unsigned long pgprot; } pgprot_t; + +# define pte_val(x) ((x).pte) +# define pmd_val(x) ((x).pmd) +# define pgd_val(x) ((x).pgd) +# define pgprot_val(x) ((x).pgprot) + +# define __pte(x) ((pte_t) { (x) } ) +# define __pgprot(x) ((pgprot_t) { (x) } ) + +#else /* !STRICT_MM_TYPECHECKS */ + /* + * .. while these make it easier on the compiler + */ +# ifndef __ASSEMBLY__ + typedef unsigned long pte_t; + typedef unsigned long pmd_t; + typedef unsigned long pgd_t; + typedef unsigned long pgprot_t; +# endif + +# define pte_val(x) (x) +# define pmd_val(x) (x) +# define pgd_val(x) (x) +# define pgprot_val(x) (x) + +# define __pte(x) (x) +# define __pgd(x) (x) +# define __pgprot(x) (x) +#endif /* !STRICT_MM_TYPECHECKS */ #define PAGE_OFFSET 0xe000000000000000 diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h --- v2.4.3/linux/include/asm-ia64/pal.h Mon Oct 9 17:54:59 2000 +++ linux/include/asm-ia64/pal.h Thu Apr 5 12:51:47 2001 @@ -1267,7 +1267,7 @@ ia64_pal_version (pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) { struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_VERSION, 0, 0, 0); + PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0); if (pal_min_version) pal_min_version->pal_version_val = iprv.v0; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/param.h linux/include/asm-ia64/param.h --- v2.4.3/linux/include/asm-ia64/param.h Fri Oct 27 11:04:43 2000 +++ linux/include/asm-ia64/param.h Thu Apr 5 12:51:47 2001 @@ -10,7 +10,7 @@ #include <linux/config.h> -#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_SOFTSDV_HACKS) +#ifdef CONFIG_IA64_HP_SIM /* * Yeah, simulating stuff is slow, so let us catch some breath between * timer interrupts... diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/perfmon.h linux/include/asm-ia64/perfmon.h --- v2.4.3/linux/include/asm-ia64/perfmon.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ia64/perfmon.h Thu Apr 5 12:51:47 2001 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com> + */ + +#ifndef _ASM_IA64_PERFMON_H +#define _ASM_IA64_PERFMON_H + +#include <linux/types.h> + +/* + * Structure used to define a context + */ +typedef struct { + unsigned long smpl_entries; /* how many entries in sampling buffer */ + unsigned long smpl_regs; /* which pmds to record on overflow */ + void *smpl_vaddr; /* returns address of BTB buffer */ + + pid_t notify_pid; /* which process to notify on overflow */ + int notify_sig; /* XXX: not used anymore */ + + int flags; /* NOBLOCK/BLOCK/ INHERIT flags (will replace API flags) */ +} pfreq_context_t; + +/* + * Structure used to configure a PMC or PMD + */ +typedef struct { + unsigned long reg_num; /* which register */ + unsigned long reg_value; /* configuration (PMC) or initial value (PMD) */ + unsigned long reg_smpl_reset; /* reset of sampling buffer overflow (large) */ + unsigned long reg_ovfl_reset; /* reset on counter overflow (small) */ + int reg_flags; /* (PMD): notify/don't notify */ +} pfreq_reg_t; + +/* + * main request structure passed by user + */ +typedef union { + pfreq_context_t pfr_ctx; /* request to configure a context */ + pfreq_reg_t pfr_reg; /* request to configure a PMD/PMC */ +} perfmon_req_t; + +extern void pfm_save_regs (struct task_struct *); +extern void pfm_load_regs (struct task_struct *); + +extern int pfm_inherit (struct task_struct *); +extern void pfm_context_exit (struct task_struct *); +extern void pfm_flush_regs (struct task_struct *); + +#endif /* _ASM_IA64_PERFMON_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h --- v2.4.3/linux/include/asm-ia64/pgalloc.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/pgalloc.h Thu Apr 5 12:51:47 2001 @@ -8,8 +8,8 @@ * This hopefully works with any (fixed) ia-64 page-size, as defined * in <asm/page.h> (currently 8192). * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000, Goutham Rao <goutham.rao@intel.com> */ @@ -28,68 +28,60 @@ * a lot of work and caused unnecessary memory traffic. How broken... * We fix this by caching them. */ -#define pgd_quicklist (my_cpu_data.pgd_quick) -#define pmd_quicklist (my_cpu_data.pmd_quick) -#define pte_quicklist (my_cpu_data.pte_quick) -#define pgtable_cache_size (my_cpu_data.pgtable_cache_sz) - -static __inline__ pgd_t* -get_pgd_slow (void) -{ - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); - if (ret) - clear_page(ret); - return ret; -} +#define pgd_quicklist (local_cpu_data->pgd_quick) +#define pmd_quicklist (local_cpu_data->pmd_quick) +#define pte_quicklist (local_cpu_data->pte_quick) +#define pgtable_cache_size (local_cpu_data->pgtable_cache_sz) -static __inline__ pgd_t* -get_pgd_fast (void) +static inline pgd_t* +pgd_alloc_one_fast (void) { unsigned long *ret = pgd_quicklist; - if (ret != NULL) { + if (__builtin_expect(ret != NULL, 1)) { pgd_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_cache_size; - } - return (pgd_t *)ret; + } else + ret = NULL; + return (pgd_t *) ret; } -static __inline__ pgd_t* +static inline pgd_t* pgd_alloc (void) { - pgd_t *pgd; + /* the VM system never calls pgd_alloc_one_fast(), so we do it here. */ + pgd_t *pgd = pgd_alloc_one_fast(); - pgd = get_pgd_fast(); - if (!pgd) - pgd = get_pgd_slow(); + if (__builtin_expect(pgd == NULL, 0)) { + pgd = (pgd_t *)__get_free_page(GFP_KERNEL); + if (__builtin_expect(pgd != NULL, 1)) + clear_page(pgd); + } return pgd; } -static __inline__ void -free_pgd_fast (pgd_t *pgd) +static inline void +pgd_free (pgd_t *pgd) { *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; ++pgtable_cache_size; } -static __inline__ pmd_t * -get_pmd_slow (void) +static inline void +pgd_populate (struct mm_struct *mm, pgd_t *pgd_entry, pmd_t *pmd) { - pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); - - if (pmd) - clear_page(pmd); - return pmd; + pgd_val(*pgd_entry) = __pa(pmd); } -static __inline__ pmd_t * -get_pmd_fast (void) + +static inline pmd_t* +pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr) { unsigned long *ret = (unsigned long *)pmd_quicklist; - if (ret != NULL) { + if (__builtin_expect(ret != NULL, 1)) { pmd_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_cache_size; @@ -97,28 +89,36 @@ return (pmd_t *)ret; } -static __inline__ void -free_pmd_fast (pmd_t *pmd) +static inline pmd_t* +pmd_alloc_one (struct mm_struct *mm, unsigned long addr) +{ + pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); + + if (__builtin_expect(pmd != NULL, 1)) + clear_page(pmd); + return pmd; +} + +static inline void +pmd_free (pmd_t *pmd) { *(unsigned long *)pmd = (unsigned long) pmd_quicklist; pmd_quicklist = (unsigned long *) pmd; ++pgtable_cache_size; } -static __inline__ void -free_pmd_slow (pmd_t *pmd) +static inline void +pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte) { - free_page((unsigned long)pmd); + pmd_val(*pmd_entry) = __pa(pte); } -extern pte_t *get_pte_slow (pmd_t *pmd, unsigned long address_preadjusted); - -static __inline__ pte_t * -get_pte_fast (void) +static inline pte_t* +pte_alloc_one_fast (struct mm_struct *mm, unsigned long addr) { unsigned long *ret = (unsigned long *)pte_quicklist; - if (ret != NULL) { + if (__builtin_expect(ret != NULL, 1)) { pte_quicklist = (unsigned long *)(*ret); ret[0] = 0; --pgtable_cache_size; @@ -126,71 +126,25 @@ return (pte_t *)ret; } -static __inline__ void -free_pte_fast (pte_t *pte) + +static inline pte_t* +pte_alloc_one (struct mm_struct *mm, unsigned long addr) { - *(unsigned long *)pte = (unsigned long) pte_quicklist; - pte_quicklist = (unsigned long *) pte; - ++pgtable_cache_size; -} + pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL); -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) -#define pmd_free(pmd) free_pmd_fast(pmd) -#define pgd_free(pgd) free_pgd_fast(pgd) - -extern void __handle_bad_pgd (pgd_t *pgd); -extern void __handle_bad_pmd (pmd_t *pmd); - -static __inline__ pte_t* -pte_alloc (pmd_t *pmd, unsigned long vmaddr) -{ - unsigned long offset; - - offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *pte_page = get_pte_fast(); - - if (!pte_page) - return get_pte_slow(pmd, offset); - pmd_set(pmd, pte_page); - return pte_page + offset; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; + if (__builtin_expect(pte != NULL, 1)) + clear_page(pte); + return pte; } -static __inline__ pmd_t* -pmd_alloc (pgd_t *pgd, unsigned long vmaddr) +static inline void +pte_free (pte_t *pte) { - unsigned long offset; - - offset = (vmaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *pmd_page = get_pmd_fast(); - - if (!pmd_page) - pmd_page = get_pmd_slow(); - if (pmd_page) { - pgd_set(pgd, pmd_page); - return pmd_page + offset; - } else - return NULL; - } - if (pgd_bad(*pgd)) { - __handle_bad_pgd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + offset; + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + ++pgtable_cache_size; } -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pmd_alloc_kernel(pgd, addr) pmd_alloc(pgd, addr) - extern int do_check_pgt_cache (int, int); /* @@ -219,7 +173,7 @@ /* * Flush a specified user mapping */ -static __inline__ void +static inline void flush_tlb_mm (struct mm_struct *mm) { if (mm) { @@ -237,7 +191,7 @@ /* * Page-granular tlb flush. */ -static __inline__ void +static inline void flush_tlb_page (struct vm_area_struct *vma, unsigned long addr) { #ifdef CONFIG_SMP @@ -300,20 +254,22 @@ * that may be necessary. */ static inline void -update_mmu_cache (struct vm_area_struct *vma, unsigned long address, pte_t pte) +update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) { + unsigned long addr; struct page *page; if (!pte_exec(pte)) return; /* not an executable page... */ page = pte_page(pte); - address &= PAGE_MASK; + /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ + addr = (unsigned long) page_address(page); if (test_bit(PG_arch_1, &page->flags)) return; /* i-cache is already coherent with d-cache */ - flush_icache_range(address, address + PAGE_SIZE); + flush_icache_range(addr, addr + PAGE_SIZE); set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h --- v2.4.3/linux/include/asm-ia64/pgtable.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/pgtable.h Thu Apr 12 12:16:36 2001 @@ -8,11 +8,12 @@ * This hopefully works with any (fixed) IA-64 page-size, as defined * in <asm/page.h> (currently 8192). * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> + #include <asm/mman.h> #include <asm/page.h> #include <asm/processor.h> @@ -103,12 +104,6 @@ */ #define PTRS_PER_PTE (__IA64_UL(1) << (PAGE_SHIFT-3)) -# ifndef __ASSEMBLY__ - -#include <asm/bitops.h> -#include <asm/mmu_context.h> -#include <asm/system.h> - /* * All the normal masks have the "page accessed" bits on, as any time * they are used, the page is accessed. They are cleared only by the @@ -126,6 +121,12 @@ #define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX) #define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX) +# ifndef __ASSEMBLY__ + +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/system.h> + /* * Next come the mappings that determine how mmap() protection bits * (PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE) get implemented. The @@ -173,7 +174,7 @@ static inline long ia64_phys_addr_valid (unsigned long addr) { - return (addr & (my_cpu_data.unimpl_pa_mask)) == 0; + return (addr & (local_cpu_data->unimpl_pa_mask)) == 0; } /* @@ -203,25 +204,12 @@ #define set_pte(ptep, pteval) (*(ptep) = (pteval)) #define RGN_SIZE (1UL << 61) -#define RGN_MAP_LIMIT (1UL << (4*PAGE_SHIFT - 12)) /* limit of mappable area in region */ +#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ #define RGN_KERNEL 7 -#define VMALLOC_START (0xa000000000000000 + 2*PAGE_SIZE) +#define VMALLOC_START (0xa000000000000000 + 3*PAGE_SIZE) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (0xa000000000000000 + RGN_MAP_LIMIT) - -/* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern pte_t ia64_bad_page (void); -extern pmd_t *ia64_bad_pagetable (void); - -#define BAD_PAGETABLE ia64_bad_pagetable() -#define BAD_PAGE ia64_bad_page() +#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) /* * Conversion functions: convert a page and protection to a page entry, @@ -251,14 +239,12 @@ /* pte_page() returns the "struct page *" corresponding to the PTE: */ #define pte_page(pte) (mem_map + (unsigned long) ((pte_val(pte) & _PFN_MASK) >> PAGE_SHIFT)) -#define pmd_set(pmdp, ptep) (pmd_val(*(pmdp)) = __pa(ptep)) #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd))) #define pmd_present(pmd) (pmd_val(pmd) != 0UL) #define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) #define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK)) -#define pgd_set(pgdp, pmdp) (pgd_val(*(pgdp)) = __pa(pmdp)) #define pgd_none(pgd) (!pgd_val(pgd)) #define pgd_bad(pgd) (!ia64_phys_addr_valid(pgd_val(pgd))) #define pgd_present(pgd) (pgd_val(pgd) != 0UL) @@ -301,7 +287,11 @@ * works bypasses the caches, but does allow for consecutive writes to * be combined into single (but larger) write transactions. */ -#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) +#ifdef CONFIG_MCKINLEY_A0_SPECIFIC +# define pgprot_writecombine(prot) prot +#else +# define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) +#endif /* * Return the region index for virtual address ADDRESS. diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h --- v2.4.3/linux/include/asm-ia64/processor.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/processor.h Thu Apr 12 12:10:25 2001 @@ -2,9 +2,9 @@ #define _ASM_IA64_PROCESSOR_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 1998-2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> * @@ -16,6 +16,8 @@ #include <linux/config.h> #include <asm/ptrace.h> +#include <asm/kregs.h> +#include <asm/system.h> #include <asm/types.h> #define IA64_NUM_DBG_REGS 8 @@ -27,6 +29,9 @@ #define IA64_NUM_PMD_REGS 32 #define IA64_NUM_PMD_COUNTERS 4 +#define DEFAULT_MAP_BASE 0x2000000000000000 +#define DEFAULT_TASK_SIZE 0xa000000000000000 + /* * TASK_SIZE really is a mis-named. It really is the maximum user * space address (plus one). On IA-64, there are five regions of 2TB @@ -163,15 +168,21 @@ #define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 3) /* don't log unaligned accesses */ #define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 4) /* generate SIGBUS on unaligned acc. */ #define IA64_THREAD_KRBS_SYNCED (__IA64_UL(1) << 5) /* krbs synced with process vm? */ -#define IA64_THREAD_MAP_SHARED (__IA64_UL(1) << 6) /* ugly: just a tmp flag for mmap() */ #define IA64_KERNEL_DEATH (__IA64_UL(1) << 63) /* see die_if_kernel()... */ #define IA64_THREAD_UAC_SHIFT 3 #define IA64_THREAD_UAC_MASK (IA64_THREAD_UAC_NOPRINT | IA64_THREAD_UAC_SIGBUS) + +/* + * This shift should be large enough to be able to represent + * 1000000/itc_freq with good accuracy while being small enough to fit + * 1000000<<IA64_USEC_PER_CYC_SHIFT in 64 bits. + */ +#define IA64_USEC_PER_CYC_SHIFT 41 + #ifndef __ASSEMBLY__ -#include <linux/smp.h> #include <linux/threads.h> #include <asm/fpu.h> @@ -220,16 +231,26 @@ }; /* - * This shift should be large enough to be able to represent - * 1000000/itc_freq with good accuracy while being small enough to fit - * 1000000<<IA64_USEC_PER_CYC_SHIFT in 64 bits. - */ -#define IA64_USEC_PER_CYC_SHIFT 41 - -/* - * CPU type, hardware bug flags, and per-CPU state. + * CPU type, hardware bug flags, and per-CPU state. Frequently used + * state comes earlier: */ struct cpuinfo_ia64 { + /* irq_stat and softirq should be 64-bit aligned */ + struct { + __u32 active; + __u32 mask; + } softirq; + union { + struct { + __u32 irq_count; + __u32 bh_count; + } f; + __u64 irq_and_bh_counts; + } irq_stat; + __u32 phys_stacked_size_p8; /* size of physical stacked registers + 8 */ + __u32 pad0; + __u64 itm_delta; /* # of clock cycles between clock ticks */ + __u64 itm_next; /* interval timer mask value to use for next clock tick */ __u64 *pgd_quick; __u64 *pmd_quick; __u64 *pte_quick; @@ -257,10 +278,15 @@ __u64 ipi_count; __u64 prof_counter; __u64 prof_multiplier; + __u64 ipi_operation; #endif -}; +} __attribute__ ((aligned (PAGE_SIZE))) ; -#define my_cpu_data cpu_data[smp_processor_id()] +/* + * The "local" data pointer. It points to the per-CPU data of the currently executing + * CPU, much like "current" points to the per-task data of the currently executing task. + */ +#define local_cpu_data ((struct cpuinfo_ia64 *) PERCPU_ADDR) extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; @@ -294,13 +320,9 @@ #ifdef CONFIG_PERFMON __u64 pmc[IA64_NUM_PMC_REGS]; __u64 pmd[IA64_NUM_PMD_REGS]; - struct { - __u64 val; /* virtual 64bit counter */ - __u64 rval; /* reset value on overflow */ - int sig; /* signal used to notify */ - int pid; /* process to notify */ - } pmu_counters[IA64_NUM_PMD_COUNTERS]; -# define INIT_THREAD_PM {0, }, {0, }, {{ 0, 0, 0, 0}, }, + unsigned long pfm_pend_notify; /* non-zero if we need to notify and block */ + void *pfm_context; /* pointer to detailed PMU context */ +# define INIT_THREAD_PM {0, }, {0, }, 0, 0, #else # define INIT_THREAD_PM #endif @@ -338,25 +360,53 @@ {0, }, /* dbr */ \ {0, }, /* ibr */ \ INIT_THREAD_PM \ - 0x2000000000000000, /* map_base */ \ - 0xa000000000000000, /* task_size */ \ + DEFAULT_MAP_BASE, /* map_base */ \ + DEFAULT_TASK_SIZE, /* task_size */ \ INIT_THREAD_IA32 \ 0 /* siginfo */ \ } -#define start_thread(regs,new_ip,new_sp) do { \ - set_fs(USER_DS); \ - ia64_psr(regs)->dfh = 1; /* disable fph */ \ - ia64_psr(regs)->mfh = 0; /* clear mfh */ \ - ia64_psr(regs)->cpl = 3; /* set user mode */ \ - ia64_psr(regs)->ri = 0; /* clear return slot number */ \ - ia64_psr(regs)->is = 0; /* IA-64 instruction set */ \ - regs->cr_iip = new_ip; \ - regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ - regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ - regs->ar_bspstore = IA64_RBS_BOT; \ - regs->ar_rnat = 0; \ - regs->loadrs = 0; \ +#define start_thread(regs,new_ip,new_sp) do { \ + set_fs(USER_DS); \ + ia64_psr(regs)->dfh = 1; /* disable fph */ \ + ia64_psr(regs)->mfh = 0; /* clear mfh */ \ + ia64_psr(regs)->cpl = 3; /* set user mode */ \ + ia64_psr(regs)->ri = 0; /* clear return slot number */ \ + ia64_psr(regs)->is = 0; /* IA-64 instruction set */ \ + regs->cr_iip = new_ip; \ + regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ + regs->ar_rnat = 0; \ + regs->ar_bspstore = IA64_RBS_BOT; \ + regs->ar_fpsr = FPSR_DEFAULT; \ + regs->loadrs = 0; \ + regs->r8 = current->dumpable; /* set "don't zap registers" flag */ \ + regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ + if (!__builtin_expect (current->dumpable, 1)) { \ + /* \ + * Zap scratch regs to avoid leaking bits between processes with different \ + * uid/privileges. \ + */ \ + regs->ar_pfs = 0; \ + regs->pr = 0; \ + /* \ + * XXX fix me: everything below can go away once we stop preserving scratch \ + * regs on a system call. \ + */ \ + regs->b6 = 0; \ + regs->r1 = 0; regs->r2 = 0; regs->r3 = 0; \ + regs->r13 = 0; regs->r14 = 0; regs->r15 = 0; \ + regs->r9 = 0; regs->r11 = 0; \ + regs->r16 = 0; regs->r17 = 0; regs->r18 = 0; regs->r19 = 0; \ + regs->r20 = 0; regs->r21 = 0; regs->r22 = 0; regs->r23 = 0; \ + regs->r24 = 0; regs->r25 = 0; regs->r26 = 0; regs->r27 = 0; \ + regs->r28 = 0; regs->r29 = 0; regs->r30 = 0; regs->r31 = 0; \ + regs->ar_ccv = 0; \ + regs->b0 = 0; regs->b7 = 0; \ + regs->f6.u.bits[0] = 0; regs->f6.u.bits[1] = 0; \ + regs->f7.u.bits[0] = 0; regs->f7.u.bits[1] = 0; \ + regs->f8.u.bits[0] = 0; regs->f8.u.bits[1] = 0; \ + regs->f9.u.bits[0] = 0; regs->f9.u.bits[1] = 0; \ + } \ } while (0) /* Forward declarations, a strange C thing... */ @@ -368,7 +418,11 @@ * parent of DEAD_TASK has collected the exist status of the task via * wait(). This is a no-op on IA-64. */ -#define release_thread(dead_task) +#ifdef CONFIG_PERFMON + extern void release_thread (struct task_struct *task); +#else +# define release_thread(dead_task) +#endif /* * This is the mechanism for creating a new kernel thread. @@ -403,20 +457,51 @@ /* Return stack pointer of blocked task TSK. */ #define KSTK_ESP(tsk) ((tsk)->thread.ksp) +static inline unsigned long +ia64_get_kr (unsigned long regnum) +{ + unsigned long r; + + switch (regnum) { + case 0: asm volatile ("mov %0=ar.k0" : "=r"(r)); break; + case 1: asm volatile ("mov %0=ar.k1" : "=r"(r)); break; + case 2: asm volatile ("mov %0=ar.k2" : "=r"(r)); break; + case 3: asm volatile ("mov %0=ar.k3" : "=r"(r)); break; + case 4: asm volatile ("mov %0=ar.k4" : "=r"(r)); break; + case 5: asm volatile ("mov %0=ar.k5" : "=r"(r)); break; + case 6: asm volatile ("mov %0=ar.k6" : "=r"(r)); break; + case 7: asm volatile ("mov %0=ar.k7" : "=r"(r)); break; + } + return r; +} + +static inline void +ia64_set_kr (unsigned long regnum, unsigned long r) +{ + switch (regnum) { + case 0: asm volatile ("mov ar.k0=%0" :: "r"(r)); break; + case 1: asm volatile ("mov ar.k1=%0" :: "r"(r)); break; + case 2: asm volatile ("mov ar.k2=%0" :: "r"(r)); break; + case 3: asm volatile ("mov ar.k3=%0" :: "r"(r)); break; + case 4: asm volatile ("mov ar.k4=%0" :: "r"(r)); break; + case 5: asm volatile ("mov ar.k5=%0" :: "r"(r)); break; + case 6: asm volatile ("mov ar.k6=%0" :: "r"(r)); break; + case 7: asm volatile ("mov ar.k7=%0" :: "r"(r)); break; + } +} + #ifndef CONFIG_SMP static inline struct task_struct * ia64_get_fpu_owner (void) { - struct task_struct *t; - __asm__ ("mov %0=ar.k5" : "=r"(t)); - return t; + return (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER); } static inline void ia64_set_fpu_owner (struct task_struct *t) { - __asm__ __volatile__ ("mov ar.k5=%0" :: "r"(t)); + ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t); } #endif /* !CONFIG_SMP */ @@ -437,8 +522,8 @@ extern void ia64_load_pm_regs (struct task_struct *task); #endif -#define ia64_fph_enable() __asm__ __volatile__ (";; rsm psr.dfh;; srlz.d;;" ::: "memory"); -#define ia64_fph_disable() __asm__ __volatile__ (";; ssm psr.dfh;; srlz.d;;" ::: "memory"); +#define ia64_fph_enable() asm volatile (";; rsm psr.dfh;; srlz.d;;" ::: "memory"); +#define ia64_fph_disable() asm volatile (";; ssm psr.dfh;; srlz.d;;" ::: "memory"); /* load fp 0.0 into fph */ static inline void @@ -467,53 +552,53 @@ static inline void ia64_fc (void *addr) { - __asm__ __volatile__ ("fc %0" :: "r"(addr) : "memory"); + asm volatile ("fc %0" :: "r"(addr) : "memory"); } static inline void ia64_sync_i (void) { - __asm__ __volatile__ (";; sync.i" ::: "memory"); + asm volatile (";; sync.i" ::: "memory"); } static inline void ia64_srlz_i (void) { - __asm__ __volatile__ (";; srlz.i ;;" ::: "memory"); + asm volatile (";; srlz.i ;;" ::: "memory"); } static inline void ia64_srlz_d (void) { - __asm__ __volatile__ (";; srlz.d" ::: "memory"); + asm volatile (";; srlz.d" ::: "memory"); } static inline __u64 ia64_get_rr (__u64 reg_bits) { __u64 r; - __asm__ __volatile__ ("mov %0=rr[%1]" : "=r"(r) : "r"(reg_bits) : "memory"); + asm volatile ("mov %0=rr[%1]" : "=r"(r) : "r"(reg_bits) : "memory"); return r; } static inline void ia64_set_rr (__u64 reg_bits, __u64 rr_val) { - __asm__ __volatile__ ("mov rr[%0]=%1" :: "r"(reg_bits), "r"(rr_val) : "memory"); + asm volatile ("mov rr[%0]=%1" :: "r"(reg_bits), "r"(rr_val) : "memory"); } static inline __u64 ia64_get_dcr (void) { __u64 r; - __asm__ ("mov %0=cr.dcr" : "=r"(r)); + asm volatile ("mov %0=cr.dcr" : "=r"(r)); return r; } static inline void ia64_set_dcr (__u64 val) { - __asm__ __volatile__ ("mov cr.dcr=%0;;" :: "r"(val) : "memory"); + asm volatile ("mov cr.dcr=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -521,14 +606,14 @@ ia64_get_lid (void) { __u64 r; - __asm__ ("mov %0=cr.lid" : "=r"(r)); + asm volatile ("mov %0=cr.lid" : "=r"(r)); return r; } static inline void ia64_invala (void) { - __asm__ __volatile__ ("invala" ::: "memory"); + asm volatile ("invala" ::: "memory"); } /* @@ -536,7 +621,7 @@ * interrupt collection and interrupt enable bits. */ #define ia64_clear_ic(flags) \ - __asm__ __volatile__ ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" \ + asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" \ : "=r"(flags) :: "memory"); /* @@ -548,13 +633,13 @@ __u64 vmaddr, __u64 pte, __u64 log_page_size) { - __asm__ __volatile__ ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); - __asm__ __volatile__ ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); + asm volatile ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); + asm volatile ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); if (target_mask & 0x1) - __asm__ __volatile__ ("itr.i itr[%0]=%1" + asm volatile ("itr.i itr[%0]=%1" :: "r"(tr_num), "r"(pte) : "memory"); if (target_mask & 0x2) - __asm__ __volatile__ (";;itr.d dtr[%0]=%1" + asm volatile (";;itr.d dtr[%0]=%1" :: "r"(tr_num), "r"(pte) : "memory"); } @@ -566,13 +651,13 @@ ia64_itc (__u64 target_mask, __u64 vmaddr, __u64 pte, __u64 log_page_size) { - __asm__ __volatile__ ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); - __asm__ __volatile__ ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); + asm volatile ("mov cr.itir=%0" :: "r"(log_page_size << 2) : "memory"); + asm volatile ("mov cr.ifa=%0;;" :: "r"(vmaddr) : "memory"); /* as per EAS2.6, itc must be the last instruction in an instruction group */ if (target_mask & 0x1) - __asm__ __volatile__ ("itc.i %0;;" :: "r"(pte) : "memory"); + asm volatile ("itc.i %0;;" :: "r"(pte) : "memory"); if (target_mask & 0x2) - __asm__ __volatile__ (";;itc.d %0;;" :: "r"(pte) : "memory"); + asm volatile (";;itc.d %0;;" :: "r"(pte) : "memory"); } /* @@ -583,16 +668,16 @@ ia64_ptr (__u64 target_mask, __u64 vmaddr, __u64 log_size) { if (target_mask & 0x1) - __asm__ __volatile__ ("ptr.i %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); + asm volatile ("ptr.i %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); if (target_mask & 0x2) - __asm__ __volatile__ ("ptr.d %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); + asm volatile ("ptr.d %0,%1" :: "r"(vmaddr), "r"(log_size << 2)); } /* Set the interrupt vector address. The address must be suitably aligned (32KB). */ static inline void ia64_set_iva (void *ivt_addr) { - __asm__ __volatile__ ("mov cr.iva=%0;; srlz.i;;" :: "r"(ivt_addr) : "memory"); + asm volatile ("mov cr.iva=%0;; srlz.i;;" :: "r"(ivt_addr) : "memory"); } /* Set the page table address and control bits. */ @@ -600,7 +685,7 @@ ia64_set_pta (__u64 pta) { /* Note: srlz.i implies srlz.d */ - __asm__ __volatile__ ("mov cr.pta=%0;; srlz.i;;" :: "r"(pta) : "memory"); + asm volatile ("mov cr.pta=%0;; srlz.i;;" :: "r"(pta) : "memory"); } static inline __u64 @@ -608,41 +693,33 @@ { __u64 r; - __asm__ ("mov %0=cpuid[%r1]" : "=r"(r) : "rO"(regnum)); + asm ("mov %0=cpuid[%r1]" : "=r"(r) : "rO"(regnum)); return r; } static inline void ia64_eoi (void) { - __asm__ ("mov cr.eoi=r0;; srlz.d;;" ::: "memory"); + asm ("mov cr.eoi=r0;; srlz.d;;" ::: "memory"); } static inline void -ia64_set_lrr0 (__u8 vector, __u8 masked) +ia64_set_lrr0 (unsigned long val) { - if (masked > 1) - masked = 1; - - __asm__ __volatile__ ("mov cr.lrr0=%0;; srlz.d" - :: "r"((masked << 16) | vector) : "memory"); + asm volatile ("mov cr.lrr0=%0;; srlz.d" :: "r"(val) : "memory"); } static inline void -ia64_set_lrr1 (__u8 vector, __u8 masked) +ia64_set_lrr1 (unsigned long val) { - if (masked > 1) - masked = 1; - - __asm__ __volatile__ ("mov cr.lrr1=%0;; srlz.d" - :: "r"((masked << 16) | vector) : "memory"); + asm volatile ("mov cr.lrr1=%0;; srlz.d" :: "r"(val) : "memory"); } static inline void ia64_set_pmv (__u64 val) { - __asm__ __volatile__ ("mov cr.pmv=%0" :: "r"(val) : "memory"); + asm volatile ("mov cr.pmv=%0" :: "r"(val) : "memory"); } static inline __u64 @@ -650,14 +727,14 @@ { __u64 retval; - __asm__ __volatile__ ("mov %0=pmc[%1]" : "=r"(retval) : "r"(regnum)); + asm volatile ("mov %0=pmc[%1]" : "=r"(retval) : "r"(regnum)); return retval; } static inline void ia64_set_pmc (__u64 regnum, __u64 value) { - __asm__ __volatile__ ("mov pmc[%0]=%1" :: "r"(regnum), "r"(value)); + asm volatile ("mov pmc[%0]=%1" :: "r"(regnum), "r"(value)); } static inline __u64 @@ -665,14 +742,14 @@ { __u64 retval; - __asm__ __volatile__ ("mov %0=pmd[%1]" : "=r"(retval) : "r"(regnum)); + asm volatile ("mov %0=pmd[%1]" : "=r"(retval) : "r"(regnum)); return retval; } static inline void ia64_set_pmd (__u64 regnum, __u64 value) { - __asm__ __volatile__ ("mov pmd[%0]=%1" :: "r"(regnum), "r"(value)); + asm volatile ("mov pmd[%0]=%1" :: "r"(regnum), "r"(value)); } /* @@ -722,7 +799,7 @@ * Get the current instruction/program counter value. */ #define current_text_addr() \ - ({ void *_pc; __asm__ ("mov %0=ip" : "=r" (_pc)); _pc; }) + ({ void *_pc; asm volatile ("mov %0=ip" : "=r" (_pc)); _pc; }) #define THREAD_SIZE IA64_STK_OFFSET /* NOTE: The task struct and the stacks are allocated together. */ @@ -740,7 +817,7 @@ static inline void ia64_set_cmcv (__u64 val) { - __asm__ __volatile__ ("mov cr.cmcv=%0" :: "r"(val) : "memory"); + asm volatile ("mov cr.cmcv=%0" :: "r"(val) : "memory"); } /* @@ -751,7 +828,7 @@ { __u64 val; - __asm__ ("mov %0=cr.cmcv" : "=r"(val) :: "memory"); + asm volatile ("mov %0=cr.cmcv" : "=r"(val) :: "memory"); return val; } @@ -759,28 +836,28 @@ ia64_get_ivr (void) { __u64 r; - __asm__ __volatile__ ("srlz.d;; mov %0=cr.ivr;; srlz.d;;" : "=r"(r)); + asm volatile ("srlz.d;; mov %0=cr.ivr;; srlz.d;;" : "=r"(r)); return r; } static inline void ia64_set_tpr (__u64 val) { - __asm__ __volatile__ ("mov cr.tpr=%0" :: "r"(val)); + asm volatile ("mov cr.tpr=%0" :: "r"(val)); } static inline __u64 ia64_get_tpr (void) { __u64 r; - __asm__ ("mov %0=cr.tpr" : "=r"(r)); + asm volatile ("mov %0=cr.tpr" : "=r"(r)); return r; } static inline void ia64_set_irr0 (__u64 val) { - __asm__ __volatile__("mov cr.irr0=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr0=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -790,14 +867,14 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr0" : "=r"(val)); + asm volatile("mov %0=cr.irr0" : "=r"(val)); return val; } static inline void ia64_set_irr1 (__u64 val) { - __asm__ __volatile__("mov cr.irr1=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr1=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -807,14 +884,14 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr1" : "=r"(val)); + asm volatile("mov %0=cr.irr1" : "=r"(val)); return val; } static inline void ia64_set_irr2 (__u64 val) { - __asm__ __volatile__("mov cr.irr2=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr2=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -824,14 +901,14 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr2" : "=r"(val)); + asm volatile("mov %0=cr.irr2" : "=r"(val)); return val; } static inline void ia64_set_irr3 (__u64 val) { - __asm__ __volatile__("mov cr.irr3=%0;;" :: "r"(val) : "memory"); + asm volatile("mov cr.irr3=%0;;" :: "r"(val) : "memory"); ia64_srlz_d(); } @@ -841,7 +918,7 @@ __u64 val; /* this is volatile because irr may change unbeknownst to gcc... */ - __asm__ __volatile__("mov %0=cr.irr3" : "=r"(val)); + asm volatile ("mov %0=cr.irr3" : "=r"(val)); return val; } @@ -850,7 +927,7 @@ { __u64 val; - __asm__ ("mov %0=gp" : "=r"(val)); + asm ("mov %0=gp" : "=r"(val)); return val; } diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/ptrace.h linux/include/asm-ia64/ptrace.h --- v2.4.3/linux/include/asm-ia64/ptrace.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/ptrace.h Thu Apr 5 12:51:47 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_PTRACE_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> * * 12/07/98 S. Eranian added pt_regs & switch_stack @@ -67,7 +67,7 @@ # define IA64_TASK_STRUCT_LOG_NUM_PAGES 0 #endif -#define IA64_RBS_OFFSET ((IA64_TASK_SIZE + 15) & ~15) +#define IA64_RBS_OFFSET ((IA64_TASK_SIZE + 15) & ~15) #define IA64_STK_OFFSET ((1 << IA64_TASK_STRUCT_LOG_NUM_PAGES)*PAGE_SIZE) #define INIT_TASK_SIZE IA64_STK_OFFSET @@ -96,11 +96,11 @@ unsigned long cr_iip; /* interrupted task's instruction pointer */ unsigned long cr_ifs; /* interrupted task's function state */ - unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ + unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ unsigned long ar_pfs; /* prev function state */ unsigned long ar_rsc; /* RSE configuration */ /* The following two are valid only if cr_ipsr.cpl > 0: */ - unsigned long ar_rnat; /* RSE NaT */ + unsigned long ar_rnat; /* RSE NaT */ unsigned long ar_bspstore; /* RSE bspstore */ unsigned long pr; /* 64 predicate registers (1 bit each) */ @@ -160,7 +160,7 @@ * "preserved" registers. */ struct switch_stack { - unsigned long caller_unat; /* user NaT collection register (preserved) */ + unsigned long caller_unat; /* user NaT collection register (preserved) */ unsigned long ar_fpsr; /* floating-point status register */ struct ia64_fpreg f2; /* preserved */ @@ -206,7 +206,7 @@ unsigned long ar_pfs; /* previous function state */ unsigned long ar_lc; /* loop counter (preserved) */ unsigned long ar_unat; /* NaT bits for r4-r7 */ - unsigned long ar_rnat; /* RSE NaT collection register */ + unsigned long ar_rnat; /* RSE NaT collection register */ unsigned long ar_bspstore; /* RSE dirty base (preserved) */ unsigned long pr; /* 64 predicate registers (1 bit each) */ }; @@ -220,22 +220,16 @@ struct task_struct; /* forward decl */ extern void show_regs (struct pt_regs *); - extern long ia64_peek (struct pt_regs *, struct task_struct *, unsigned long addr, long *val); - extern long ia64_poke (struct pt_regs *, struct task_struct *, unsigned long addr, long val); - extern void ia64_flush_fph (struct task_struct *t); - extern void ia64_sync_fph (struct task_struct *t); + extern unsigned long ia64_get_user_bsp (struct task_struct *, struct pt_regs *); + extern long ia64_peek (struct task_struct *, unsigned long, unsigned long, long *); + extern long ia64_poke (struct task_struct *, unsigned long, unsigned long, long); + extern void ia64_flush_fph (struct task_struct *); + extern void ia64_sync_fph (struct task_struct *); -#ifdef CONFIG_IA64_NEW_UNWIND /* get nat bits for scratch registers such that bit N==1 iff scratch register rN is a NaT */ extern unsigned long ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat); /* put nat bits for scratch registers such that scratch register rN is a NaT iff bit N==1 */ extern unsigned long ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat); -#else - /* get nat bits for r1-r31 such that bit N==1 iff rN is a NaT */ - extern long ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw); - /* put nat bits for r1-r31 such that rN is a NaT iff bit N==1 */ - extern void ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat); -#endif extern void ia64_increment_ip (struct pt_regs *pt); extern void ia64_decrement_ip (struct pt_regs *pt); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sal.h linux/include/asm-ia64/sal.h --- v2.4.3/linux/include/asm-ia64/sal.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/sal.h Thu Apr 12 12:16:36 2001 @@ -16,7 +16,6 @@ * (plus examples of platform error info structures from smariset @ Intel) */ -#include <linux/config.h> #include <linux/spinlock.h> #include <asm/pal.h> @@ -28,15 +27,12 @@ #define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7) \ result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7) -#ifdef CONFIG_SMP -# define SAL_CALL(result,args...) do { \ - spin_lock(&sal_lock); \ - __SAL_CALL(result,args); \ - spin_unlock(&sal_lock); \ +# define SAL_CALL(result,args...) do { \ + unsigned long flags; \ + spin_lock_irqsave(&sal_lock, flags); \ + __SAL_CALL(result,args); \ + spin_unlock_irqrestore(&sal_lock, flags); \ } while (0) -#else -# define SAL_CALL(result,args...) __SAL_CALL(result,args) -#endif #define SAL_SET_VECTORS 0x01000000 #define SAL_GET_STATE_INFO 0x01000001 @@ -440,11 +436,10 @@ * machine state at the time of MCA's, INITs or CMCs */ static inline s64 -ia64_sal_clear_state_info (u64 sal_info_type, u64 sal_info_sub_type) +ia64_sal_clear_state_info (u64 sal_info_type) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, sal_info_sub_type, - 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, 0, 0, 0, 0, 0); return isrv.status; } @@ -453,10 +448,10 @@ * state at the time of the MCAs, INITs or CMCs. */ static inline u64 -ia64_sal_get_state_info (u64 sal_info_type, u64 sal_info_sub_type, u64 *sal_info) +ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_GET_STATE_INFO, sal_info_type, sal_info_sub_type, + SAL_CALL(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, sal_info, 0, 0, 0, 0); if (isrv.status) return 0; @@ -466,11 +461,10 @@ * state at the time of MCAs, INITs or CMCs */ static inline u64 -ia64_sal_get_state_info_size (u64 sal_info_type, u64 sal_info_sub_type) +ia64_sal_get_state_info_size (u64 sal_info_type) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, sal_info_sub_type, - 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, 0, 0, 0, 0, 0); if (isrv.status) return 0; return isrv.v0; @@ -492,11 +486,10 @@ * non-monarch processor at the end of machine check processing. */ static inline s64 -ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout) +ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout, u64 rz_always) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, timeout, - 0, 0, 0); + SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, timeout, rz_always, 0, 0); return isrv.status; } diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/segment.h linux/include/asm-ia64/segment.h --- v2.4.3/linux/include/asm-ia64/segment.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/segment.h Thu Apr 5 12:51:47 2001 @@ -3,4 +3,4 @@ /* Only here because we have some old header files that expect it.. */ -#endif /* __ALPHA_SEGMENT_H */ +#endif /* _ASM_IA64_SEGMENT_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/semaphore.h linux/include/asm-ia64/semaphore.h --- v2.4.3/linux/include/asm-ia64/semaphore.h Mon Oct 9 17:55:00 2000 +++ linux/include/asm-ia64/semaphore.h Tue Apr 17 17:19:31 2001 @@ -7,6 +7,7 @@ */ #include <linux/wait.h> +#include <linux/rwsem.h> #include <asm/atomic.h> @@ -116,208 +117,6 @@ #endif if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} - -/* - * rw mutexes (should that be mutices? =) -- throw rw spinlocks and - * semaphores together, and this is what we end up with... - * - * The lock is initialized to BIAS. This way, a writer subtracts BIAS - * ands gets 0 for the case of an uncontended lock. Readers decrement - * by 1 and see a positive value when uncontended, negative if there - * are writers waiting (in which case it goes to sleep). BIAS must be - * chosen such that subtracting BIAS once per CPU will result either - * in zero (uncontended case) or in a negative value (contention - * case). On the other hand, BIAS must be at least as big as the - * number of processes in the system. - * - * On IA-64, we use a BIAS value of 0x100000000, which supports up to - * 2 billion (2^31) processors and 4 billion processes. - * - * In terms of fairness, when there is heavy use of the lock, we want - * to see the lock being passed back and forth between readers and - * writers (like in a producer/consumer style of communication). - * - * -ben (with clarifications & IA-64 comments by davidm) - */ -#define RW_LOCK_BIAS 0x100000000ul - -struct rw_semaphore { - volatile long count; - volatile __u8 write_bias_granted; - volatile __u8 read_bias_granted; - __u16 pad1; - __u32 pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -# define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -# define __RWSEM_DEBUG_INIT -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ \ - (count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT \ -} - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS - 1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0) - -extern void __down_read_failed (struct rw_semaphore *sem, long count); -extern void __down_write_failed (struct rw_semaphore *sem, long count); -extern void __rwsem_wake (struct rw_semaphore *sem, long count); - -static inline void -init_rwsem (struct rw_semaphore *sem) -{ - sem->count = RW_LOCK_BIAS; - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -static inline void -down_read (struct rw_semaphore *sem) -{ - long count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = ia64_fetch_and_add(-1, &sem->count); - if (count < 0) - __down_read_failed(sem, count); - -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -static inline void -down_write (struct rw_semaphore *sem) -{ - long old_count, new_count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - do { - old_count = sem->count; - new_count = old_count - RW_LOCK_BIAS; - } while (cmpxchg_acq(&sem->count, old_count, new_count) != old_count); - - if (new_count != 0) - __down_write_failed(sem, new_count); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* - * When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -static inline void -__up_read (struct rw_semaphore *sem) -{ - long count; - - count = ia64_fetch_and_add(1, &sem->count); - if (count == 0) - /* - * Other processes are blocked already; resolve - * contention by letting either a writer or a reader - * proceed... - */ - __rwsem_wake(sem, count); -} - -/* - * Releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -static inline void -__up_write (struct rw_semaphore *sem) -{ - long old_count, new_count; - - do { - old_count = sem->count; - new_count = old_count + RW_LOCK_BIAS; - } while (cmpxchg_rel(&sem->count, old_count, new_count) != old_count); - - /* - * Note: new_count <u RW_LOCK_BIAS <=> old_count < 0 && new_count >= 0. - * (where <u is "unsigned less-than"). - */ - if ((unsigned long) new_count < RW_LOCK_BIAS) - /* someone is blocked already, resolve contention... */ - __rwsem_wake(sem, new_count); -} - -static inline void -up_read (struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -static inline void -up_write (struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); } #endif /* _ASM_IA64_SEMAPHORE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sigcontext.h linux/include/asm-ia64/sigcontext.h --- v2.4.3/linux/include/asm-ia64/sigcontext.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/sigcontext.h Thu Apr 5 12:51:47 2001 @@ -36,6 +36,7 @@ unsigned long sc_ar_lc; /* loop count register */ unsigned long sc_pr; /* predicate registers */ unsigned long sc_br[8]; /* branch registers */ + /* Note: sc_gr[0] is used as the "uc_link" member of ucontext_t */ unsigned long sc_gr[32]; /* general registers (static partition) */ struct ia64_fpreg sc_fr[128]; /* floating-point registers */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/siginfo.h linux/include/asm-ia64/siginfo.h --- v2.4.3/linux/include/asm-ia64/siginfo.h Mon Oct 9 17:55:00 2000 +++ linux/include/asm-ia64/siginfo.h Thu Apr 5 12:51:47 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_SIGINFO_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/types.h> @@ -66,6 +66,12 @@ long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ int _fd; } _sigpoll; + /* SIGPROF */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + unsigned long _pfm_ovfl_counters; /* which PMU counter overflowed */ + } _sigprof; } _sifields; } siginfo_t; @@ -85,6 +91,7 @@ #define si_isr _sifields._sigfault._isr /* valid if si_code==FPE_FLTxxx */ #define si_band _sifields._sigpoll._band #define si_fd _sifields._sigpoll._fd +#define si_pfm_ovfl _sifields._sigprof._pfm_ovfl_counters /* * si_code values @@ -98,6 +105,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) +#define __SI_PROF (6 << 16) #define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) #else #define __SI_KILL 0 @@ -201,12 +209,16 @@ #define NSIGPOLL 6 /* + * SIGPROF si_codes + */ +#define PROF_OVFL (__SI_PROF|1) /* some counters overflowed */ + +/* * sigevent definitions - * - * It seems likely that SIGEV_THREAD will have to be handled from - * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the - * thread manager then catches and does the appropriate nonsense. - * However, everything is written out here so as to not get lost. + * + * It seems likely that SIGEV_THREAD will have to be handled from userspace, libpthread + * transmuting it to SIGEV_SIGNAL, which the thread manager then catches and does the + * appropriate nonsense. However, everything is written out here so as to not get lost. */ #define SIGEV_SIGNAL 0 /* notify via signal */ #define SIGEV_NONE 1 /* other notification: meaningless */ @@ -246,6 +258,7 @@ } extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); +extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h --- v2.4.3/linux/include/asm-ia64/smp.h Mon Oct 9 17:55:00 2000 +++ linux/include/asm-ia64/smp.h Thu Apr 5 12:51:47 2001 @@ -3,6 +3,8 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #ifndef _ASM_IA64_SMP_H #define _ASM_IA64_SMP_H @@ -15,13 +17,14 @@ #include <linux/threads.h> #include <linux/kernel.h> -#include <asm/ptrace.h> #include <asm/io.h> +#include <asm/processor.h> +#include <asm/ptrace.h> #define XTP_OFFSET 0x1e0008 -#define SMP_IRQ_REDIRECTION (1 << 0) -#define SMP_IPI_REDIRECTION (1 << 1) +#define SMP_IRQ_REDIRECTION (1 << 0) +#define SMP_IPI_REDIRECTION (1 << 1) #define smp_processor_id() (current->processor) @@ -30,15 +33,15 @@ int cpu_phys_id[NR_CPUS]; } smp_boot_data __initdata; +extern char no_int_routing __initdata; + extern unsigned long cpu_present_map; extern unsigned long cpu_online_map; extern unsigned long ipi_base_addr; -extern int bootstrap_processor; -extern volatile int __cpu_physical_id[NR_CPUS]; +extern int __cpu_physical_id[NR_CPUS]; extern unsigned char smp_int_redirect; -extern char no_int_routing; extern int smp_num_cpus; - + #define cpu_physical_id(i) __cpu_physical_id[i] #define cpu_number_map(i) (i) #define cpu_logical_map(i) (i) @@ -54,54 +57,55 @@ { int i; - for (i=0; i<smp_num_cpus; i++) { - if (cpu_physical_id(i) == cpuid) + for (i = 0; i < smp_num_cpus; ++i) + if (cpu_physical_id(i) == (__u32) cpuid) break; - } return i; } /* * XTP control functions: - * min_xtp : route all interrupts to this CPU - * normal_xtp: nominal XTP value - * max_xtp : never deliver interrupts to this CPU. + * min_xtp : route all interrupts to this CPU + * normal_xtp: nominal XTP value + * max_xtp : never deliver interrupts to this CPU. */ static inline void -min_xtp(void) +min_xtp (void) { if (smp_int_redirect & SMP_IRQ_REDIRECTION) writeb(0x00, ipi_base_addr | XTP_OFFSET); /* XTP to min */ } static inline void -normal_xtp(void) +normal_xtp (void) { if (smp_int_redirect & SMP_IRQ_REDIRECTION) writeb(0x08, ipi_base_addr | XTP_OFFSET); /* XTP normal */ } static inline void -max_xtp(void) +max_xtp (void) { if (smp_int_redirect & SMP_IRQ_REDIRECTION) writeb(0x0f, ipi_base_addr | XTP_OFFSET); /* Set XTP to max */ } static inline unsigned int -hard_smp_processor_id(void) +hard_smp_processor_id (void) { - struct { - unsigned long reserved : 16; - unsigned long eid : 8; - unsigned long id : 8; - unsigned long ignored : 32; + union { + struct { + unsigned long reserved : 16; + unsigned long eid : 8; + unsigned long id : 8; + unsigned long ignored : 32; + } f; + unsigned long bits; } lid; - __asm__ ("mov %0=cr.lid" : "=r" (lid)); - - return lid.id << 8 | lid.eid; + lid.bits = ia64_get_lid(); + return lid.f.id << 8 | lid.f.eid; } #define NO_PROC_ID (-1) @@ -111,7 +115,7 @@ extern void smp_do_timer (struct pt_regs *regs); extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info, - int retry, int wait); + int retry, int wait); #endif /* CONFIG_SMP */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/smplock.h linux/include/asm-ia64/smplock.h --- v2.4.3/linux/include/asm-ia64/smplock.h Thu Mar 23 12:50:09 2000 +++ linux/include/asm-ia64/smplock.h Thu Apr 5 12:51:47 2001 @@ -3,10 +3,12 @@ * * Default SMP lock implementation */ -#include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/sched.h> -#include <asm/spinlock.h> +#include <asm/current.h> +#include <asm/hardirq.h> extern spinlock_t kernel_flag; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/addrs.h linux/include/asm-ia64/sn/addrs.h --- v2.4.3/linux/include/asm-ia64/sn/addrs.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/addrs.h Thu Apr 5 12:51:47 2001 @@ -11,6 +11,7 @@ #define _ASM_SN_ADDRS_H #include <linux/config.h> + #if _LANGUAGE_C #include <linux/types.h> #endif /* _LANGUAGE_C */ @@ -21,22 +22,15 @@ #include <asm/sn/kldir.h> #endif /* CONFIG_IA64_SGI_SN1 */ -#if defined(CONFIG_IA64_SGI_IO) #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/addrs.h> #endif -#endif /* CONFIG_IA64_SGI_IO */ #if _LANGUAGE_C -#if defined(CONFIG_IA64_SGI_IO) /* FIXME */ #define PS_UINT_CAST (__psunsigned_t) #define UINT64_CAST (uint64_t) -#else /* CONFIG_IA64_SGI_IO */ -#define PS_UINT_CAST (unsigned long) -#define UINT64_CAST (unsigned long) -#endif /* CONFIG_IA64_SGI_IO */ #define HUBREG_CAST (volatile hubreg_t *) @@ -138,6 +132,8 @@ #define UALIAS_BASE HSPEC_BASE #define UALIAS_SIZE 0x10000000 /* 256 Megabytes */ +#define CPU_UALIAS 0x20000 /* 128 Kilobytes */ +#define UALIAS_CPU_SIZE (CPU_UALIAS / CPUS_PER_NODE) #define UALIAS_LIMIT (UALIAS_BASE + UALIAS_SIZE) /* @@ -408,24 +404,19 @@ #define PHYS_RAMBASE 0x0 #define K0_RAMBASE PHYS_TO_K0(PHYS_RAMBASE) -#define EX_HANDLER_OFFSET(slice) ((slice) << 16) -#define EX_HANDLER_ADDR(nasid, slice) \ - PHYS_TO_K0(NODE_OFFSET(nasid) | EX_HANDLER_OFFSET(slice)) -#define EX_HANDLER_SIZE 0x0400 - -#define EX_FRAME_OFFSET(slice) ((slice) << 16 | 0x400) -#define EX_FRAME_ADDR(nasid, slice) \ - PHYS_TO_K0(NODE_OFFSET(nasid) | EX_FRAME_OFFSET(slice)) -#define EX_FRAME_SIZE 0x0c00 - #define ARCS_SPB_OFFSET 0x1000 #define ARCS_SPB_ADDR(nasid) \ PHYS_TO_K0(NODE_OFFSET(nasid) | ARCS_SPB_OFFSET) #define ARCS_SPB_SIZE 0x0400 #define KLDIR_OFFSET 0x2000 +#ifndef __ia64 #define KLDIR_ADDR(nasid) \ TO_NODE_UNCAC((nasid), KLDIR_OFFSET) +#else +#define KLDIR_ADDR(nasid) \ + TO_NODE_CAC((nasid), KLDIR_OFFSET) +#endif #define KLDIR_SIZE 0x0400 diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/agent.h linux/include/asm-ia64/sn/agent.h --- v2.4.3/linux/include/asm-ia64/sn/agent.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/agent.h Thu Apr 5 12:51:47 2001 @@ -13,6 +13,7 @@ #define _ASM_SGI_SN_AGENT_H #include <linux/config.h> + #include <asm/sn/addrs.h> #include <asm/sn/arch.h> //#include <asm/sn/io.h> diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/arc/hinv.h linux/include/asm-ia64/sn/arc/hinv.h --- v2.4.3/linux/include/asm-ia64/sn/arc/hinv.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/arc/hinv.h Thu Apr 5 12:51:47 2001 @@ -89,7 +89,7 @@ PCIAdapter, GIOAdapter, TPUAdapter, - + TernaryCache, Anonymous } CONFIGTYPE; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/arch.h linux/include/asm-ia64/sn/arch.h --- v2.4.3/linux/include/asm-ia64/sn/arch.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/arch.h Thu Apr 5 12:51:47 2001 @@ -15,12 +15,10 @@ #include <linux/types.h> #include <linux/config.h> -#if defined(CONFIG_IA64_SGI_IO) #include <asm/sn/types.h> #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_SGI_IP37) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/arch.h> #endif -#endif /* CONFIG_IA64_SGI_IO */ #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) @@ -68,7 +66,7 @@ * cputolocalslice - returns a number 0..1 that identifies the local slice of * the cpu within it's PI interface. */ -#ifdef notyet +#ifdef LATER /* These are dummied up for now ..... */ #define cputocnode(cpu) \ (pdaindr[(cpu)].p_nodeid) @@ -86,7 +84,7 @@ #define cputoslice(cpu) 0 #define cputolocalslice(cpu) 0 #define cputosubnode(cpu) 0 -#endif /* notyet */ +#endif /* LATER */ #endif /* CONFIG_SGI_IP35 */ #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) @@ -131,6 +129,7 @@ ((nnode) >> \ (is_fine_dirmode() ? NASID_TO_FINEREG_SHFT : NASID_TO_COARSEREG_SHFT)) +#ifndef __ia64 extern cnodeid_t nasid_to_compact_node[MAX_NASIDS]; extern nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; extern cnodeid_t cpuid_to_compact_node[MAXCPUS]; @@ -153,6 +152,17 @@ #define COMPACT_TO_NASID_NODEID(cnode) compact_to_nasid_nodeid(cnode) #define CPUID_TO_COMPACT_NODEID(cpu) (cpuid_to_compact_node[(cpu)]) #endif + +#else + +/* + * IA64 specific nasid and cnode ids. + */ +#define NASID_TO_COMPACT_NODEID(nasid) (nasid_to_cnodeid(nasid)) +#define COMPACT_TO_NASID_NODEID(cnode) (cnodeid_to_nasid(cnode)) +#define CPUID_TO_COMPACT_NODEID(cpu) (cpuid_to_cnodeid(cpu)) + +#endif /* #ifndef __ia64 */ extern int node_getlastslot(cnodeid_t); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/cdl.h linux/include/asm-ia64/sn/cdl.h --- v2.4.3/linux/include/asm-ia64/sn/cdl.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/cdl.h Thu Apr 5 12:51:47 2001 @@ -30,6 +30,15 @@ cdl_iter_f (devfs_handle_t vhdl); /* + * cdl_drv_f is the type for the functions + * that are called by cdl_add_driver and + * cdl_del_driver. + */ + +typedef void +cdl_drv_f (devfs_handle_t vhdl, int key1, int key2, int error); + +/* * If CDL_PRI_HI is specified in the flags * parameter for cdl_add_driver, then that driver's * attach routine will be called for future connect @@ -73,8 +82,10 @@ * * Calls the driver's attach routine with all * connection points on the list that have the same - * key information as the driver; then places the - * driver on the list so that any connection points + * key information as the driver; call-back the + * specified function to notify the driver of the + * attach status for each device. Place the driver + * on the list so that any connection points * discovered in the future that match the driver * can be handed off to the driver's attach * routine. @@ -86,14 +97,17 @@ int key1, int key2, char *prefix, - int flags); + int flags, + cdl_drv_f *func); /* * cdl_del_driver: remove a device driver * * Calls the driver's detach routine with all * connection points on the list that match the - * driver; then forgets about the driver. Future + * driver; call-back the specified function to + * notify the driver of the detach status for each + * device. Then forget about the driver. Future * calls to cdl_add_connpt with connections that * would match this driver no longer trigger calls * to the driver's attach routine. @@ -107,7 +121,8 @@ * was successful. */ extern void cdl_del_driver(cdl_p reg, - char *prefix); + char *prefix, + cdl_drv_f *func); /* * cdl_add_connpt: add a connection point @@ -124,7 +139,8 @@ extern int cdl_add_connpt(cdl_p reg, int key1, int key2, - devfs_handle_t conn); + devfs_handle_t conn, + int drv_flags); /* * cdl_del_connpt: delete a connection point @@ -138,10 +154,11 @@ * NOTE: Same caveat here about the detach calls as * in the cdl_del_driver() comment above. */ -extern void cdl_del_connpt(cdl_p reg, +extern int cdl_del_connpt(cdl_p reg, int key1, int key2, - devfs_handle_t conn); + devfs_handle_t conn, + int drv_flags); /* * cdl_iterate: find all verticies in the registry @@ -162,7 +179,7 @@ */ struct async_attach_s { - sema_t async_sema; + struct semaphore async_sema; int async_count; }; typedef struct async_attach_s *async_attach_t; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/cmn_err.h linux/include/asm-ia64/sn/cmn_err.h --- v2.4.3/linux/include/asm-ia64/sn/cmn_err.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/cmn_err.h Wed Dec 31 16:00:00 1969 @@ -1,120 +0,0 @@ -/* $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 - */ -#ifndef _ASM_SN_CMN_ERR_H -#define _ASM_SN_CMN_ERR_H - -/* -** Common error handling severity levels. Converted to be -** represented by the associated 4.3BSD syslog priorities. -*/ - -#define CE_DEBUG KERN_DEBUG /* debug */ -#define CE_CONT KERN_INFO /* continuation */ -#define CE_NOTE KERN_NOTICE /* notice */ -#define CE_WARN KERN_WARNING /* warning */ -#define CE_ALERT KERN_ALERT /* alert */ -#define CE_PANIC KERN_EMERG /* panic */ - -#define CE_LEVELMASK LOG_PRIMASK /* mask for severity level */ -#define CE_CPUID 0x8 /* prepend CPU id to output */ -#define CE_PHYSID 0x10 /* prepend CPU phys location */ -#define CE_SYNC 0x20 /* wait for uart to drain before returning */ - -/* Flags for Availmon Monitoring - * When a developer or's these bits into the cmn_err flags above, - * and they have availmon installed, certain "actions" will take - * place depending upon how they have the availmon software configured. - */ -#define CE_TOOKACTIONS 0x0100 /* Actions taken by some error */ -#define CE_RUNNINGPOOR 0x0200 /* System running degraded */ -#define CE_MAINTENANCE 0x0400 /* System needs maintenance */ -#define CE_CONFIGERROR 0x0800 /* System configured incorrectly */ - -/* Bitmasks for separating subtasks from priority levels */ -#define CE_PRIOLEVELMASK 0x00ff /* bitmask for severity levels of cmn_err */ -#define CE_SUBTASKMASK 0xff00 /* bitmask for availmon actions of cmn_err */ -#define CE_AVAILMONALL (CE_TOOKACTIONS|CE_RUNNINGPOOR| \ - CE_MAINTENANCE|CE_CONFIGERROR) - -#ifdef __KERNEL__ - -#define CE_PBPANIC KERN_CRIT /* Special define used to manipulate - * putbufndx in kernel */ - -/* Console output flushing flag and routine */ - -extern int constrlen; /* Length of current console string, if zero, - there are no characters to flush */ -#define CONBUF_LOCKED 0 /* conbuf is already locked */ -#define CONBUF_UNLOCKED 1 /* need to reacquire lock */ -#define CONBUF_DRAIN 2 /* ensure output before returning */ - -/* - * bit field descriptions for printf %r and %R formats - * - * printf("%r %R", val, reg_descp); - * struct reg_desc *reg_descp; - * - * the %r and %R formats allow formatted print of bit fields. individual - * bit fields are described by a struct reg_desc, multiple bit fields within - * a single word can be described by multiple reg_desc structures. - * %r outputs a string of the format "<bit field descriptions>" - * %R outputs a string of the format "0x%x<bit field descriptions>" - * - * The fields in a reg_desc are: - * __psunsigned_t rd_mask; An appropriate mask to isolate the bit field - * within a word, and'ed with val - * - * int rd_shift; A shift amount to be done to the isolated - * bit field. done before printing the isolate - * bit field with rd_format and before searching - * for symbolic value names in rd_values - * - * char *rd_name; If non-null, a bit field name to label any - * out from rd_format or searching rd_values. - * if neither rd_format or rd_values is non-null - * rd_name is printed only if the isolated - * bit field is non-null. - * - * char *rd_format; If non-null, the shifted bit field value - * is printed using this format. - * - * struct reg_values *rd_values; If non-null, a pointer to a table - * matching numeric values with symbolic names. - * rd_values are searched and the symbolic - * value is printed if a match is found, if no - * match is found "???" is printed. - * - */ - - -/* - * register values - * map between numeric values and symbolic values - */ -struct reg_values { - __psunsigned_t rv_value; - char *rv_name; -}; - -/* - * register descriptors are used for formatted prints of register values - * rd_mask and rd_shift must be defined, other entries may be null - */ -struct reg_desc { - k_machreg_t rd_mask; /* mask to extract field */ - int rd_shift; /* shift for extracted value, - >>, + << */ - char *rd_name; /* field name */ - char *rd_format; /* format to print field */ - struct reg_values *rd_values; /* symbolic names of values */ -}; - -#endif /* __KERNEL__ */ -#endif /* _ASM_SN_CMN_ERR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/dmamap.h linux/include/asm-ia64/sn/dmamap.h --- v2.4.3/linux/include/asm-ia64/sn/dmamap.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/dmamap.h Thu Apr 5 12:51:47 2001 @@ -10,6 +10,8 @@ #ifndef _ASM_SN_DMAMAP_H #define _ASM_SN_DMAMAP_H +#include <asm/sn/sv.h> + #ifdef __cplusplus extern "C" { #endif @@ -53,7 +55,7 @@ extern int dma_map(dmamap_t *, caddr_t, int); extern int dma_map2(dmamap_t *, caddr_t, caddr_t, int); extern paddr_t dma_mapaddr(dmamap_t *, caddr_t); -#ifdef IRIX +#ifdef LATER extern int dma_mapbp(dmamap_t *, buf_t *, int); #endif extern int dma_map_alenlist(dmamap_t *, struct alenlist_s *, size_t); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/eeprom.h linux/include/asm-ia64/sn/eeprom.h --- v2.4.3/linux/include/asm-ia64/sn/eeprom.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/eeprom.h Thu Apr 5 12:51:47 2001 @@ -349,7 +349,7 @@ * is ignored. */ -#ifdef IRIX +#ifdef LATER char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, net_vec_t path ); #endif @@ -363,7 +363,7 @@ * if the part and mfg numbers stored there indicate that this widget * is an XBridge (and so must be part of a brick). */ -#ifdef IRIX +#ifdef LATER int is_iobrick( int nasid, int widget_num ); #endif @@ -371,11 +371,7 @@ * address passed to it and uses is_iobrick to determine whether * the widget in question is part of an SN1 IO brick. */ -#ifdef IRIX #define IS_IOBRICK(rg) is_iobrick( NASID_GET((rg)), SWIN_WIDGETNUM((rg)) ) -#else -#define IS_IOBRICK(rg) 1 -#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/gda.h linux/include/asm-ia64/sn/gda.h --- v2.4.3/linux/include/asm-ia64/sn/gda.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/gda.h Thu Apr 5 12:51:47 2001 @@ -61,7 +61,7 @@ /* Pointer to a mask of nodes with copies * of the kernel. */ char g_padding[56]; /* pad out to 128 bytes */ - nasid_t g_nasidtable[MAX_COMPACT_NODES]; /* NASID of each node, + nasid_t g_nasidtable[MAX_COMPACT_NODES+1]; /* NASID of each node, * indexed by cnodeid. */ } gda_t; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/hack.h linux/include/asm-ia64/sn/hack.h --- v2.4.3/linux/include/asm-ia64/sn/hack.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/hack.h Thu Apr 5 12:51:47 2001 @@ -22,6 +22,10 @@ typedef int cred_t; /* This is for compilation reasons */ struct cred { int x; }; + +#define mrlock(_s, _t, _u) +#define mrunlock(_s) + /* * Hardware Graph routines that are currently stubbed! */ @@ -34,50 +38,26 @@ * Routines redefined to use linux equivalents. * ************************************************/ -#define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) +/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */ -#define sv_init(a,b,c) FIXME("Fixme: sv_init : no-op") -#define sv_wait(a,b,c,d) FIXME("Fixme: sv_wait : no-op") -#define sv_broadcast(a) FIXME("Fixme: sv_broadcast : no-op") -#define sv_destroy(a) FIXME("Fixme: sv_destroy : no-op") +#define FIXME(s) extern devfs_handle_t dummy_vrtx; #define cpuid_to_vertex(cpuid) dummy_vrtx /* (pdaindr[cpuid].pda->p_vertex) */ #define PUTBUF_LOCK(a) { FIXME("PUTBUF_LOCK"); } #define PUTBUF_UNLOCK(a) { FIXME("PUTBUF_UNLOCK"); } -static inline int sv_signal(sv_t *a) {FIXME("sv_signal : return 0"); return (0); } - -#define cmn_err(x,y...) { FIXME("cmn_err : use printk"); printk(x y); } typedef int (*splfunc_t)(void); -extern int badaddr_val(volatile void *, int , volatile void *); - -extern int cap_able_cred(uint64_t a, uint64_t b); - -#define _CAP_CRABLE(cr,c) (cap_able_cred(cr,c)) -#define CAP_MEMORY_MGT (0x01LL << 25) -#define CAP_DEVICE_MGT (0x01LL << 37) - -#define io_splock(l) l -#define io_spunlock(l,s) /* move to stubs.c yet */ -#define spinlock_destroy(a) /* needed by pcibr_detach() */ -#define mutex_spinlock(a) 0 -#define mutex_spinunlock(a,b) -#define mutex_spinlock_spl(x,y) y -#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) printk("Fixme: v_mapphys - soft->base 0x%p\n", b); +#define v_mapphys(a,b,c) 0 // printk("Fixme: v_mapphys - soft->base 0x%p\n", b); #define splhi() 0 #define spl7 splhi() #define splx(s) -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); extern void * kmem_alloc_node(register size_t, register int, cnodeid_t); extern void * kmem_zalloc(size_t, int); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/hcl.h linux/include/asm-ia64/sn/hcl.h --- v2.4.3/linux/include/asm-ia64/sn/hcl.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/hcl.h Thu Apr 5 12:51:47 2001 @@ -13,6 +13,7 @@ extern spinlock_t hcl_spinlock; extern devfs_handle_t hcl_handle; /* HCL driver */ extern devfs_handle_t hwgraph_root; +extern devfs_handle_t linux_busnum; typedef long labelcl_info_place_t; @@ -22,7 +23,6 @@ /* Support for INVENTORY */ struct inventory_s; struct invplace_s; -extern struct invplace_s invplace_none; /* diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/hwcntrs.h linux/include/asm-ia64/sn/hwcntrs.h --- v2.4.3/linux/include/asm-ia64/sn/hwcntrs.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/hwcntrs.h Thu Apr 5 12:51:47 2001 @@ -73,7 +73,6 @@ } rcb_slot_t; #if defined(__KERNEL__) -// #include <sys/immu.h> typedef struct sn0_refcnt_args_32 { uint64_t vaddr; uint64_t len; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/intr.h linux/include/asm-ia64/sn/intr.h --- v2.4.3/linux/include/asm-ia64/sn/intr.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/intr.h Thu Apr 5 12:51:47 2001 @@ -10,6 +10,9 @@ #ifndef _ASM_SN_INTR_H #define _ASM_SN_INTR_H +/* Subnode wildcard */ +#define SUBNODE_ANY -1 + /* Number of interrupt levels associated with each interrupt register. */ #define N_INTPEND_BITS 64 @@ -24,8 +27,6 @@ #if LANGUAGE_C -#if defined(CONFIG_IA64_SGI_IO) - #define II_NAMELEN 24 /* @@ -36,7 +37,7 @@ intr_func_t iv_func; /* Interrupt handler function */ intr_func_t iv_prefunc; /* Interrupt handler prologue func */ void *iv_arg; /* Argument to pass to handler */ -#ifdef IRIX +#ifdef LATER thd_int_t iv_tinfo; /* Thread info */ #endif cpuid_t iv_mustruncpu; /* Where we must run. */ @@ -93,7 +94,7 @@ call an intr routine. */ intr_info_t info[N_INTPEND_BITS]; /* information needed only to maintain interrupts. */ - lock_t vector_lock; /* Lock for this and the + spinlock_t vector_lock; /* Lock for this and the masks in the PDA. */ splfunc_t vector_spl; /* vector_lock req'd spl */ int vector_state; /* Initialized to zero. @@ -122,15 +123,12 @@ #define hub_intrinfo0 private.p_intmasks.dispatch0->info #define hub_intrinfo1 private.p_intmasks.dispatch1->info -#endif /* CONFIG_IA64_SGI_IO */ - /* * Macros to manipulate the interrupt register on the calling hub chip. */ #define LOCAL_HUB_SEND_INTR(_level) LOCAL_HUB_S(PI_INT_PEND_MOD, \ (0x100|(_level))) -#if defined(CONFIG_IA64_SGI_IO) #define REMOTE_HUB_PI_SEND_INTR(_hub, _sn, _level) \ REMOTE_HUB_PI_S((_hub), _sn, PI_INT_PEND_MOD, (0x100|(_level))) @@ -138,7 +136,6 @@ REMOTE_HUB_PI_S(cputonasid(_cpuid), \ SUBNODE(cputoslice(_cpuid)), \ PI_INT_PEND_MOD, (0x100|(_level))) -#endif /* CONFIG_IA64_SGI_IO*/ /* * When clearing the interrupt, make sure this clear does make it @@ -153,7 +150,6 @@ REMOTE_HUB_PI_S((_hub), (_sn), PI_INT_PEND_MOD, (_level)), \ REMOTE_HUB_PI_L((_hub), (_sn), PI_INT_PEND0) -#if defined(CONFIG_IA64_SGI_IO) /* Special support for use by gfx driver only. Supports special gfx hub interrupt. */ extern void install_gfxintr(cpuid_t cpu, ilvl_t swlevel, intr_func_t intr_func, void *intr_arg); @@ -164,7 +160,6 @@ */ extern void intr_block_bit(cpuid_t cpu, int bit); extern void intr_unblock_bit(cpuid_t cpu, int bit); -#endif /* CONFIG_IA64_SGI_IO */ #endif /* LANGUAGE_C */ @@ -246,6 +241,13 @@ # define IO_ERROR_INTR 38 /* set up by prom */ # define DEBUG_INTR_B 37 /* used by symmon to stop all cpus */ # define DEBUG_INTR_A 36 +#endif + +#ifdef CONFIG_IA64_SGI_SN1 +// These aren't strictly accurate or complete. See the +// Synergy Spec. for details. +#define SGI_UART_IRQ (65) +#define SGI_HUB_ERROR_IRQ (182) #endif #endif /* _ASM_SN_INTR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/intr_public.h linux/include/asm-ia64/sn/intr_public.h --- v2.4.3/linux/include/asm-ia64/sn/intr_public.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/intr_public.h Thu Apr 5 12:51:47 2001 @@ -7,9 +7,10 @@ * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Colin Ngam */ -#ifndef __SYS_SN_INTR_PUBLIC_H__ -#define __SYS_SN_INTR_PUBLIC_H__ +#ifndef _ASM_SN_INTR_PUBLIC_H__ +#define _ASM_SN_INTR_PUBLIC_H__ +#include <linux/config.h> /* REMEMBER: If you change these, the whole world needs to be recompiled. * It would also require changing the hubspl.s code and SN0/intr.c @@ -22,7 +23,6 @@ #define INTPEND0_MAXMASK (N_INTPEND0_MASKS - 1) #define INTPEND1_MAXMASK (N_INTPEND1_MASKS - 1) -#include <linux/config.h> #if _LANGUAGE_C #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/arch.h> @@ -56,5 +56,4 @@ } hub_intmasks_t; #endif /* _LANGUAGE_C */ -#endif /* __SYS_SN_INTR_PUBLIC_H__ */ - +#endif /* _ASM_SN_INTR_PUBLIC_H__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/invent.h linux/include/asm-ia64/sn/invent.h --- v2.4.3/linux/include/asm-ia64/sn/invent.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/invent.h Thu Apr 5 12:51:47 2001 @@ -30,6 +30,10 @@ #define app32_ptr_t unsigned long #define graph_vertex_place_t long #define GRAPH_VERTEX_NONE ((devfs_handle_t)-1) +#define GRAPH_EDGE_PLACE_NONE ((graph_edge_place_t)0) +#define GRAPH_INFO_PLACE_NONE ((graph_info_place_t)0) +#define GRAPH_VERTEX_PLACE_NONE ((graph_vertex_place_t)0) + typedef struct inventory_s { struct inventory_s *inv_next; /* next inventory record in list */ @@ -105,6 +109,8 @@ #define INV_RPS 23 /* redundant power source */ #define INV_TPU 24 /* Tensor Processing Unit */ #define INV_FCNODE 25 /* Helper class for SCSI classes, not in classes[] */ +#define INV_USB 26 /* Universal Serial Bus */ +#define INV_1394NODE 27 /* helper class for 1394/SPB2 classes, not in classes[] */ /* types for class processor */ #define INV_CPUBOARD 1 @@ -187,8 +193,11 @@ #define INV_QL_12160 17 /* qlogic 12160 */ #define INV_QL_2100 18 /* qLogic 2100 Fibrechannel */ #define INV_QL_2200 19 /* qLogic 2200 Fibrechannel */ -#define INV_SBP2 20 /* SBP2 protocol over OHCI on 1394 */ - +#define INV_PR_HIO_D 20 /* Prisa HIO Dual channel */ +#define INV_PR_PCI64_D 21 /* Prisa PCI-64 Dual channel */ +#define INV_QL_2200A 22 /* qLogic 2200A Fibrechannel */ +#define INV_SBP2 23 /* SBP2 protocol over OHCI on 1394 */ +#define INV_QL_2300 24 /* qLogic 2300 Fibrechannel */ /* states for INV_SCSIDRIVE type of class disk */ @@ -215,6 +224,7 @@ #define INV_SIDCACHE 8 #define INV_MAIN_MB 9 #define INV_HUBSPC 10 /* HUBSPC */ +#define INV_TIDCACHE 11 /* types for class serial */ #define INV_CDSIO 1 /* Central Data serial board */ @@ -405,6 +415,7 @@ #define INV_NET_ISDN_PRI 8 /* PRI ISDN */ #define INV_NET_HIPPIS 9 /* HIPPI-Serial */ #define INV_NET_GSN 10 /* GSN (aka HIPPI-6400) */ +#define INV_NET_MYRINET 11 /* Myricom PCI network */ /* controllers for network types, unique within class network */ #define INV_ETHER_EC 0 /* IP6 integral controller */ @@ -463,6 +474,7 @@ #define INV_OPTICAL 7 /* optical disks (read-write) */ #define INV_CHANGER 8 /* jukebox's for CDROMS, for example */ #define INV_COMM 9 /* Communications device */ +#define INV_STARCTLR 12 /* Storage Array Controller */ #define INV_RAIDCTLR 32 /* RAID ctlr actually gives type 0 */ /* bit definitions for state field for class INV_SCSI */ @@ -495,6 +507,7 @@ #define INV_VIDEO_RACER 11 /* SpeedRacer Pro Video */ #define INV_VIDEO_EVO 12 /* EVO Personal Video */ #define INV_VIDEO_XTHD 13 /* XIO XT-HDTV video */ +#define INV_VIDEO_XTDIGVID 14 /* XIO XT-HDDIGVID video */ /* states for video class INV_VIDEO_EXPRESS */ @@ -568,10 +581,7 @@ #define INV_7of9_PANEL 5 /* 7of9 flatpanel board and panel */ /* types for class INV_IEEE1394 */ -#define INV_OHCI 0 /* Ohci IEEE1394 pci card */ -#define INV_RAWISO1394 10 /* Raw Isochronous IEEE 1394 protocol driver */ -#define INV_RAWASYNC1394 11 /* Raw Asynchronous IEEE 1394 protocol driver */ -#define INV_AVC1394 12 /* Audio, Video & Control (AV/C) IEEE 1394 protocol driver */ +#define INV_OHCI 0 /* Ohci IEEE1394 pci card */ /* state for class INV_IEEE1394 & type INV_OHCI */ #define INV_IEEE1394_STATE_TI_REV_1 0 @@ -583,6 +593,51 @@ #define INV_TPU_EXT 0 /* External XIO Tensor Processing Unit */ #define INV_TPU_XIO 1 /* Internal XIO Tensor Processing Unit */ +/* + * USB Types. The upper 8 bits contain general usb device class and are used to + * qualify the lower 8 bits which contain device type within a usb class. + * Use USB_INV_DEVCLASS and USB_INV_DEVTYPE to to decode an i_type, and + * USB_INV_TYPE to set it. + */ + +#define USB_INV_DEVCLASS(invtype) ((invtype) >> 8) +#define USB_INV_DEVTYPE(invtype) ((invtype) & 0xf) +#define USB_INV_TYPE(usbclass, usbtype) (((usbclass) << 8) | (usbtype)) + +/* + * USB device classes. These classes might not match the classes as defined + * by the usb spec, but where possible we will try. + */ + +#define USB_INV_CLASS_RH 0x00 /* root hub (ie. controller) */ +#define USB_INV_CLASS_HID 0x03 /* human interface device */ +#define USB_INV_CLASS_HUB 0x09 /* hub device */ + +/* + * USB device types within a class. These will not match USB device types, + * as the usb is not consistent on how specific types are defined (sometimes + * they are found in the interface subclass, sometimes (as in HID devices) they + * are found within data generated by the device (hid report descriptors for + * example). + */ + +/* + * RH types + */ + +#define USB_INV_RH_OHCI 0x01 /* ohci root hub */ + +/* + * HID types + */ + +#define USB_INV_HID_KEYBOARD 0x01 /* kbd (HID class) */ +#define USB_INV_HID_MOUSE 0x02 /* mouse (HID class) */ + +/* + * HUB types - none yet + */ + typedef struct invent_generic_s { unsigned short ig_module; unsigned short ig_slot; @@ -618,6 +673,8 @@ cpu_inv_t ic_cpu_info; unsigned short ic_cpuid; unsigned short ic_slice; + unsigned short ic_cpumode; + } invent_cpuinfo_t; typedef struct invent_rpsinfo { @@ -659,9 +716,14 @@ inventory_t *invplace_inv; /* place in inv list on vertex */ } invplace_t; /* Magic cookie placeholder in inventory list */ +extern invplace_t invplace_none; +#define INVPLACE_NONE invplace_none + extern void add_to_inventory(int, int, int, int, int); extern void replace_in_inventory(inventory_t *, int, int, int, int, int); +extern void start_scan_inventory(invplace_t *); extern inventory_t *get_next_inventory(invplace_t *); +extern void end_scan_inventory(invplace_t *); extern inventory_t *find_inventory(inventory_t *, int, int, int, int, int); extern int scaninvent(int (*)(inventory_t *, void *), void *); extern int get_sizeof_inventory(int); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/io.h linux/include/asm-ia64/sn/io.h --- v2.4.3/linux/include/asm-ia64/sn/io.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/io.h Thu Apr 5 12:51:47 2001 @@ -12,20 +12,12 @@ #define _ASM_SN_IO_H #include <linux/config.h> + #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/addrs.h> #endif -#define IO_SPACE_BASE IO_BASE - /* Because we only have PCI I/O ports. */ -#if !defined(CONFIG_IA64_SGI_IO) -#define IO_SPACE_LIMIT 0xffffffff - -/* No isa_* versions, the Origin doesn't have ISA / EISA bridges. */ - -#else /* CONFIG_IA64_SGI_IO */ - #define IIO_ITTE_BASE 0x400160 /* base of translation table entries */ #define IIO_ITTE(bigwin) (IIO_ITTE_BASE + 8*(bigwin)) @@ -71,7 +63,5 @@ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/hubio.h> #endif - -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_IO_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ioerror.h linux/include/asm-ia64/sn/ioerror.h --- v2.4.3/linux/include/asm-ia64/sn/ioerror.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/ioerror.h Thu Apr 5 12:51:47 2001 @@ -10,6 +10,7 @@ #ifndef _ASM_SN_IOERROR_H #define _ASM_SN_IOERROR_H +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) /* * Macros defining the various Errors to be handled as part of @@ -177,6 +178,7 @@ MODE_DEVREENABLE /* Reenable pass */ } ioerror_mode_t; +#endif /* C || C++ */ typedef int error_handler_f(void *, int, ioerror_mode_t, ioerror_t *); typedef void *error_handler_arg_t; diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ioerror_handling.h linux/include/asm-ia64/sn/ioerror_handling.h --- v2.4.3/linux/include/asm-ia64/sn/ioerror_handling.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/ioerror_handling.h Thu Apr 5 12:51:47 2001 @@ -12,7 +12,7 @@ #include <linux/config.h> -#ifdef __KERNEL__ +#if __KERNEL__ /* * Basic types required for io error handling interfaces. @@ -255,7 +255,7 @@ int code = 0; /* Check if we have a valid hwgraph vertex */ -#ifdef IRIX +#ifdef LATER if (!dev_is_vertex(v)) return(code); #endif @@ -276,18 +276,6 @@ } ASSERT(v_error_skip_env_get(v, error_env) == GRAPH_SUCCESS); code = setjmp(*error_env); -#ifdef IRIX - /* NOTE: It might be OK to leave the allocated jump buffer on the - * vertex. This can be used for later purposes. - */ - if (code) { - /* This is the case where a long jump has been taken from one - * one of the error handling interfaces. - */ - if (v_error_skip_env_clear(v, error_env) == GRAPH_SUCCESS) - kfree(error_env); - } -#endif return(code); } #endif /* CONFIG_SGI_IO_ERROR_HANDLING */ @@ -309,8 +297,6 @@ * thru the calls the io error handling layer. */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) -#define IS_DEVICE_SHUTDOWN(_d) (error_state_get(_d) == ERROR_STATE_SHUTDOWN) -#else extern boolean_t is_device_shutdown(devfs_handle_t); #define IS_DEVICE_SHUTDOWN(_d) (is_device_shutdown(_d)) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/iograph.h linux/include/asm-ia64/sn/iograph.h --- v2.4.3/linux/include/asm-ia64/sn/iograph.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/iograph.h Thu Apr 5 12:51:47 2001 @@ -90,6 +90,7 @@ #define EDGE_LBL_PROM "prom" #define EDGE_LBL_RACK "rack" #define EDGE_LBL_RDISK "rdisk" +#define EDGE_LBL_REPEATER_ROUTER "repeaterrouter" #define EDGE_LBL_ROUTER "router" #define EDGE_LBL_RPOS "bay" /* Position in rack */ #define EDGE_LBL_SCSI "scsi" @@ -117,9 +118,9 @@ #define EDGE_LBL_RPS "rps" /* redundant power supply */ #define EDGE_LBL_XBOX_RPS "xbox_rps" /* redundant power supply for xbox unit */ #define EDGE_LBL_IOBRICK "iobrick" -#define EDGE_LBL_PBRICK "pbrick" -#define EDGE_LBL_IBRICK "ibrick" -#define EDGE_LBL_XBRICK "xbrick" +#define EDGE_LBL_PBRICK "Pbrick" +#define EDGE_LBL_IBRICK "Ibrick" +#define EDGE_LBL_XBRICK "Xbrick" #define EDGE_LBL_CPUBUS "cpubus" /* CPU Interfaces (SysAd) */ /* vertex info labels in hwgraph */ @@ -134,6 +135,8 @@ #define INFO_LBL_DKIOTIME "_dkiotime" #define INFO_LBL_DRIVER "_driver" /* points to attached device_driver_t */ #define INFO_LBL_ELSC "_elsc" +#define INFO_LBL_SUBCH "_subch" /* system controller subchannel */ +#define INFO_LBL_L1SCP "_l1scp" /* points to l1sc_t */ #define INFO_LBL_FC_PORTNAME "_fc_portname" #define INFO_LBL_GIOIO "_gioio" #define INFO_LBL_GFUNCS "_gioio_ops" /* ops vector for gio providers */ @@ -196,5 +199,21 @@ #if defined(__KERNEL__) void init_all_devices(void); #endif /* __KERNEL__ */ + +#include <asm/sn/xtalk/xbow.h> /* For get MAX_PORT_NUM */ + +int io_brick_map_widget(char, int); +int io_path_map_widget(devfs_handle_t); + +/* + * Map a brick's widget number to a meaningful int + */ + +struct io_brick_map_s { + char ibm_type; /* brick type, e.g. */ + /* 'I' for Ibrick */ + int ibm_map_wid[MAX_PORT_NUM]; /* wid to int map */ +}; + #endif /* _ASM_SN_IOGRAPH_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/klconfig.h linux/include/asm-ia64/sn/klconfig.h --- v2.4.3/linux/include/asm-ia64/sn/klconfig.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/klconfig.h Thu Apr 5 12:51:47 2001 @@ -12,6 +12,8 @@ #ifndef _ASM_SN_KLCONFIG_H #define _ASM_SN_KLCONFIG_H +#include <linux/config.h> + /* * klconfig.h */ @@ -32,7 +34,6 @@ * that offsets of existing fields do not change. */ -#include <linux/config.h> #include <linux/types.h> #include <asm/sn/types.h> #include <asm/sn/slotnum.h> @@ -60,11 +61,10 @@ #define SIZE_PAD 4096 /* 4k padding for structures */ #if (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP) /* MAX_SLOTS_PER_NODE??? */ /* - * 1 NODE brick, 2 Router bricks (1 local, 1 meta), 6 XIO Widgets, - * 1 Midplane (midplane will likely become IO brick when Bruce cleans - * up IP35 klconfig) + * 1 NODE brick, 3 Router bricks (1 local, 1 meta, 1 repeater), + * 6 XIO Widgets, 1 Xbow, 1 gfx */ -#define MAX_SLOTS_PER_NODE (1 + 2 + 6 + 1) +#define MAX_SLOTS_PER_NODE (1 + 3 + 6 + 1 + 1) #else /* * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets, @@ -88,7 +88,7 @@ #define VISITED_BOARD 0x08 /* Used for compact hub numbering. */ #define LOCAL_MASTER_IO6 0x10 /* master io6 for that node */ #define GLOBAL_MASTER_IO6 0x20 -#define THIRD_NIC_PRESENT 0x40 /* for future use */ +#define GLOBAL_MASTER_EXT 0x40 /* extend master io6 to other bus on ibrick */ #define SECOND_NIC_PRESENT 0x80 /* addons like MIO are present */ /* klinfo->flags fields */ @@ -119,15 +119,9 @@ typedef struct console_s { -#if defined(CONFIG_IA64_SGI_IO) /* FIXME */ __psunsigned_t uart_base; __psunsigned_t config_base; __psunsigned_t memory_base; -#else - unsigned long uart_base; - unsigned long config_base; - unsigned long memory_base; -#endif short baud; short flag; int type; @@ -164,18 +158,20 @@ #define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off) \ (KL_CONFIG_HDR(_nasid)->ch_board_info = (_off)) -#if !defined(SIMULATED_KLGRAPH) +#ifndef __ia64 #define KL_CONFIG_INFO(_nasid) \ (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ? \ NODE_OFFSET_TO_K0((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \ 0) #else -/* - * For Fake klgraph info. - */ -extern kl_config_hdr_t *linux_klcfg; -#define KL_CONFIG_INFO(_nasid) (lboard_t *)((ulong)linux_klcfg->ch_board_info | 0xe000000000000000) -#endif /* CONFIG_IA64_SGI_IO */ +#define NODE_OFFSET_TO_LBOARD(nasid,off) (lboard_t*)(NODE_CAC_BASE(nasid) + (off)) + +#define KL_CONFIG_INFO(_nasid) \ + (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ? \ + NODE_OFFSET_TO_LBOARD((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \ + NULL) + +#endif /* __ia64 */ #define KL_CONFIG_MAGIC(_nasid) (KL_CONFIG_HDR(_nasid)->ch_magic) @@ -187,23 +183,13 @@ /* --- New Macros for the changed kl_config_hdr_t structure --- */ -#if defined(CONFIG_IA64_SGI_IO) #define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ ((__psunsigned_t)_k + (_k->ch_malloc_hdr_off))) -#else -#define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ - (unsigned long)_k + (_k->ch_malloc_hdr_off))) -#endif #define KL_CONFIG_CH_MALLOC_HDR(_n) PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n)) -#if defined(CONFIG_IA64_SGI_IO) #define PTR_CH_CONS_INFO(_k) ((console_t *)\ ((__psunsigned_t)_k + (_k->ch_cons_off))) -#else -#define PTR_CH_CONS_INFO(_k) ((console_t *)\ - ((unsigned long)_k + (_k->ch_cons_off))) -#endif #define KL_CONFIG_CH_CONS_INFO(_n) PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n)) @@ -374,6 +360,7 @@ #define KLTYPE_IP27 (KLCLASS_CPU | 0x1) /* 2 CPUs(R10K) per board */ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #define KLTYPE_IP35 KLTYPE_IP27 +#define KLTYPE_IP37 KLTYPE_IP35 #endif #define KLTYPE_WEIRDIO (KLCLASS_IO | 0x0) @@ -394,6 +381,8 @@ #define KLTYPE_TPU (KLCLASS_IO | 0xB) /* Tensor Processing Unit */ #define KLTYPE_GSN_A (KLCLASS_IO | 0xC) /* Main GSN board */ #define KLTYPE_GSN_B (KLCLASS_IO | 0xD) /* Auxiliary GSN board */ +#define KLTYPE_SHOEHORN (KLCLASS_IO | 0xE) +#define KLTYPE_SERIAL_HIPPI (KLCLASS_IO | 0xF) #define KLTYPE_GFX (KLCLASS_GFX | 0x0) /* unknown graphics type */ #define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* KONA graphics on IP27 */ @@ -404,11 +393,12 @@ #define KLTYPE_ROUTER2 KLTYPE_ROUTER /* Obsolete! */ #define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2) #define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3) +#define KLTYPE_REPEATER_ROUTER (KLCLASS_ROUTER | 0x4) #define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0) #define KLTYPE_MIDPLANE8 (KLCLASS_MIDPLANE | 0x1) /* 8 slot backplane */ #define KLTYPE_MIDPLANE KLTYPE_MIDPLANE8 -#define KLTYPE_PBRICK_XBOW (KLCLASS_MIDPLANE | 0x2) +#define KLTYPE_IOBRICK_XBOW (KLCLASS_MIDPLANE | 0x2) #define KLTYPE_IOBRICK (KLCLASS_IOBRICK | 0x0) #define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) @@ -485,7 +475,7 @@ #define KLCF_NUM_COMPS(_brd) ((_brd)->brd_numcompts) #define KLCF_MODULE_ID(_brd) ((_brd)->brd_module) -#ifndef SIMULATED_KLGRAPH +#ifndef __ia64 #define KLCF_NEXT(_brd) ((_brd)->brd_next ? (lboard_t *)((_brd)->brd_next): NULL) #define KLCF_COMP(_brd, _ndx) \ (klinfo_t *)(NODE_OFFSET_TO_K0(NASID_GET(_brd), \ @@ -494,14 +484,18 @@ (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo)) #else -/* - * For fake klgraph info. - */ -#define KLCF_COMP(_brd, _ndx) (klinfo_t *)((ulong) 0xe000000000000000 |((_brd)->brd_compts[(_ndx)])) -#define KLCF_NEXT(_brd) ((_brd)->brd_next ? (lboard_t *)((ulong) 0xe000000000000000 | (_brd->brd_next)) : NULL) -#define KLCF_COMP_ERROR(_brd, _comp) (_brd = _brd , (_comp)->errinfo) -#endif /* SIMULATED_KLGRAPH */ +#define NODE_OFFSET_TO_KLINFO(n,off) ((klinfo_t*) TO_NODE_CAC(n,off)) +#define KLCF_NEXT(_brd) \ + ((_brd)->brd_next ? \ + (NODE_OFFSET_TO_LBOARD(NASID_GET(_brd), (_brd)->brd_next)): NULL) +#define KLCF_COMP(_brd, _ndx) \ + (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)])) + +#define KLCF_COMP_ERROR(_brd, _comp) \ + (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo)) + +#endif /* __ia64 */ #define KLCF_COMP_TYPE(_comp) ((_comp)->struct_type) #define KLCF_BRIDGE_W_ID(_comp) ((_comp)->physid) /* Widget ID */ @@ -581,6 +575,11 @@ #define KLSTRUCT_GSN_A 29 #define KLSTRUCT_GSN_B 30 #define KLSTRUCT_XTHD 31 +#define KLSTRUCT_QLFIBRE 32 +#define KLSTRUCT_1394 33 +#define KLSTRUCT_USB 34 +#define KLSTRUCT_USBKBD 35 +#define KLSTRUCT_USBMS 36 /* * These are the indices of various components within a lboard structure. @@ -845,6 +844,15 @@ mio_t mio_specific ; } klmio_t ; +/* + * USB info + */ + +typedef struct klusb_s { + klinfo_t usb_info; /* controller info */ + void *usb_bus; /* handle to usb_bus_t */ + uint64_t usb_controller; /* ptr to controller info */ +} klusb_t ; typedef union klcomp_s { klcpu_t kc_cpu; @@ -862,6 +870,7 @@ klfddi_t kc_fddi; klmio_t kc_mio; klmod_serial_num_t kc_snum ; + klusb_t kc_usb; } klcomp_t; typedef union kldev_s { /* for device structure allocation */ @@ -925,7 +934,6 @@ extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int); -#if defined(CONFIG_IA64_SGI_IO) extern xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx); extern devfs_handle_t nodevertex_xbow_peer_get(devfs_handle_t node_vtx); extern lboard_t *find_gfxpipe(int pipenum); @@ -954,8 +962,5 @@ extern int is_master_baseio(nasid_t,moduleid_t,slotid_t); extern nasid_t get_actual_nasid(lboard_t *brd) ; extern net_vec_t klcfg_discover_route(lboard_t *, lboard_t *, int); -#else /* CONFIG_IA64_SGI_IO */ -extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu); -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_KLCONFIG_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/kldir.h linux/include/asm-ia64/sn/kldir.h --- v2.4.3/linux/include/asm-ia64/sn/kldir.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/kldir.h Thu Apr 5 12:51:47 2001 @@ -13,9 +13,7 @@ #define _ASM_SN_KLDIR_H #include <linux/config.h> -#if defined(CONFIG_IA64_SGI_IO) #include <asm/sn/sgi.h> -#endif /* * The kldir memory area resides at a fixed place in each node's memory and @@ -136,88 +134,11 @@ #define KLDIR_OFF_STRIDE 0x28 #endif /* LANGUAGE_ASSEMBLY */ -#if !defined(CONFIG_IA64_SGI_IO) - -/* - * This is defined here because IP27_SYMMON_STK_SIZE must be at least what - * we define here. Since it's set up in the prom. We can't redefine it later - * and expect more space to be allocated. The way to find out the true size - * of the symmon stacks is to divide SYMMON_STK_SIZE by SYMMON_STK_STRIDE - * for a particular node. - */ -#define SYMMON_STACK_SIZE 0x8000 - -#if defined (PROM) || defined (SABLE) - -/* - * These defines are prom version dependent. No code other than the IP27 - * prom should attempt to use these values. - */ -#define IP27_LAUNCH_OFFSET 0x2400 -#define IP27_LAUNCH_SIZE 0x400 -#define IP27_LAUNCH_COUNT 2 -#define IP27_LAUNCH_STRIDE 0x200 - -#define IP27_KLCONFIG_OFFSET 0x4000 -#define IP27_KLCONFIG_SIZE 0xc000 -#define IP27_KLCONFIG_COUNT 1 -#define IP27_KLCONFIG_STRIDE 0 - -#define IP27_NMI_OFFSET 0x3000 -#define IP27_NMI_SIZE 0x40 -#define IP27_NMI_COUNT 2 -#define IP27_NMI_STRIDE 0x40 - -#define IP27_PI_ERROR_OFFSET 0x12000 -#define IP27_PI_ERROR_SIZE 0x4000 -#define IP27_PI_ERROR_COUNT 1 -#define IP27_PI_ERROR_STRIDE 0 - -#define IP27_SYMMON_STK_OFFSET 0x25000 -#define IP27_SYMMON_STK_SIZE 0xe000 -#define IP27_SYMMON_STK_COUNT 2 -/* IP27_SYMMON_STK_STRIDE must be >= SYMMON_STACK_SIZE */ -#define IP27_SYMMON_STK_STRIDE 0x7000 - -#define IP27_FREEMEM_OFFSET 0x19000 -#define IP27_FREEMEM_SIZE -1 -#define IP27_FREEMEM_COUNT 1 -#define IP27_FREEMEM_STRIDE 0 - -#endif /* PROM || SABLE*/ -/* - * There will be only one of these in a partition so the IO6 must set it up. - */ -#define IO6_GDA_OFFSET 0x11000 -#define IO6_GDA_SIZE 0x400 -#define IO6_GDA_COUNT 1 -#define IO6_GDA_STRIDE 0 - -/* - * save area of kernel nmi regs in the prom format - */ -#define IP27_NMI_KREGS_OFFSET 0x11400 -#define IP27_NMI_KREGS_CPU_SIZE 0x200 -/* - * save area of kernel nmi regs in eframe format - */ -#define IP27_NMI_EFRAME_OFFSET 0x11800 -#define IP27_NMI_EFRAME_SIZE 0x200 - -#define KLDIR_ENT_SIZE 0x40 -#define KLDIR_MAX_ENTRIES (0x400 / 0x40) - -#endif /* !CONFIG_IA64_SGI_IO */ - #ifdef _LANGUAGE_C typedef struct kldir_ent_s { u64 magic; /* Indicates validity of entry */ off_t offset; /* Offset from start of node space */ -#if defined(CONFIG_IA64_SGI_IO) /* FIXME */ __psunsigned_t pointer; /* Pointer to area in some cases */ -#else - unsigned long pointer; /* Pointer to area in some cases */ -#endif size_t size; /* Size in bytes */ u64 count; /* Repeat count if array, 1 if not */ size_t stride; /* Stride if array, 0 if not */ @@ -227,7 +148,6 @@ } kldir_ent_t; #endif /* _LANGUAGE_C */ -#if defined(CONFIG_IA64_SGI_IO) #define KLDIR_ENT_SIZE 0x40 #define KLDIR_MAX_ENTRIES (0x400 / 0x40) @@ -240,7 +160,5 @@ #else #error "kldir.h is currently defined for IP27 and IP35 platforms only" #endif - -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_KLDIR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ksys/elsc.h linux/include/asm-ia64/sn/ksys/elsc.h --- v2.4.3/linux/include/asm-ia64/sn/ksys/elsc.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/ksys/elsc.h Thu Apr 5 12:51:47 2001 @@ -11,6 +11,7 @@ #define _ASM_SN_KSYS_ELSC_H #include <linux/config.h> + #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/ksys/l1.h> #endif @@ -48,7 +49,7 @@ int elsc_msg_callback(elsc_t *e, void (*callback)(void *callback_data, char *msg), void *callback_data); -#if 0 +#ifdef LATER char *elsc_errmsg(int code); int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len); @@ -68,7 +69,7 @@ */ int elsc_version(elsc_t *e, char *result); -#if 0 +#ifdef LATER int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2); int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2); #endif @@ -90,7 +91,7 @@ int elsc_unlock(elsc_t *e); int elsc_display_char(elsc_t *e, int led, int chr); int elsc_display_digit(elsc_t *e, int led, int num, int l_case); -#if 0 +#ifdef LATER int elsc_display_mesg(elsc_t *e, char *chr); /* 8-char input */ int elsc_password_set(elsc_t *e, char *password); /* 4-char input */ int elsc_password_get(elsc_t *e, char *password); /* 4-char output */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/ksys/l1.h linux/include/asm-ia64/sn/ksys/l1.h --- v2.4.3/linux/include/asm-ia64/sn/ksys/l1.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/ksys/l1.h Thu Apr 5 12:51:47 2001 @@ -80,11 +80,11 @@ * use == BRL1_SUBCH_FREE */ uint target; /* type, rack and slot of component to * which this subchannel is directed */ - int packet_arrived; /* true if packet arrived on + atomic_t packet_arrived; /* true if packet arrived on * this subchannel */ sc_cq_t * iqp; /* input queue for this subchannel */ sv_t arrive_sv; /* used to wait for a packet */ - lock_t data_lock; /* synchronize access to input queues and + spinlock_t data_lock; /* synchronize access to input queues and * other fields of the brl1_sch_s struct */ brl1_notif_t tx_notify; /* notify higher layer that transmission may * continue */ @@ -118,9 +118,7 @@ brl1_uartf_t putc_f; /* pointer to UART putc function */ brl1_uartf_t getc_f; /* pointer to UART getc function */ - lock_t send_lock; /* arbitrates send synchronization */ - lock_t recv_lock; /* arbitrates uart receive access */ - lock_t subch_lock; /* arbitrates subchannel allocation */ + spinlock_t subch_lock; /* arbitrates subchannel allocation */ cpuid_t intr_cpu; /* cpu that receives L1 interrupts */ u_char send_in_use; /* non-zero if send buffer contains an @@ -223,6 +221,7 @@ #define L1_RESP_REQC (-101) /* bad request code */ #define L1_RESP_NAVAIL (-104) /* requested data not available */ #define L1_RESP_ARGVAL (-105) /* arg value out of range */ +#define L1_RESP_INVAL (-107) /* requested data invalid */ /* L1 general requests */ @@ -239,16 +238,19 @@ #define L1_REQ_PORTSPEED 0x000a /* get ioport speed */ #define L1_REQ_CONS_SUBCH 0x1002 /* select this node's console - * subchannel */ + subchannel */ #define L1_REQ_CONS_NODE 0x1003 /* volunteer to be the master - * (console-hosting) node */ + (console-hosting) node */ #define L1_REQ_DISP1 0x1004 /* write line 1 of L1 display */ #define L1_REQ_DISP2 0x1005 /* write line 2 of L1 display */ #define L1_REQ_PARTITION_SET 0x1006 /* set partition id */ #define L1_REQ_EVENT_SUBCH 0x1007 /* set the subchannel for system controller event transmission */ -#define L1_REQ_RESET 0x2001 /* request a full system reset */ +#define L1_REQ_RESET 0x2000 /* request a full system reset */ +#define L1_REQ_PCI_UP 0x2001 /* power up pci slot or bus */ +#define L1_REQ_PCI_DOWN 0x2002 /* power down pci slot or bus */ +#define L1_REQ_PCI_RESET 0x2003 /* reset pci bus or slot */ /* L1 command interpreter requests */ @@ -325,18 +327,6 @@ void sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ); void sc_intr_enable( l1sc_t *sc ); -#if 0 -int sc_portspeed_get( l1sc_t *sc ); -#endif - -int l1_cons_poll( l1sc_t *sc ); -int l1_cons_getc( l1sc_t *sc ); -void l1_cons_init( l1sc_t *sc ); -int l1_cons_read( l1sc_t *sc, char *buf, int avail ); -int l1_cons_write( l1sc_t *sc, char *msg, int len, int wait ); -void l1_cons_tx_notif( l1sc_t *sc, brl1_notif_t func ); -void l1_cons_rx_notif( l1sc_t *sc, brl1_notif_t func ); - int _elscuart_putc( l1sc_t *sc, int c ); int _elscuart_getc( l1sc_t *sc ); int _elscuart_poll( l1sc_t *sc ); @@ -354,11 +344,7 @@ int elsc_display_line(l1sc_t *e, char *line, int lnum); extern l1sc_t *get_elsc( void ); -extern void set_elsc( l1sc_t *e ); - #define get_l1sc get_elsc -#define set_l1sc(e) set_elsc(e) - #define get_master_l1sc get_l1sc int router_module_get( nasid_t nasid, net_vec_t path ); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/mmzone.h linux/include/asm-ia64/sn/mmzone.h --- v2.4.3/linux/include/asm-ia64/sn/mmzone.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/mmzone.h Thu Apr 5 12:51:47 2001 @@ -6,6 +6,7 @@ #define _LINUX_ASM_SN_MMZONE_H #include <linux/config.h> + #include <asm/sn/mmzone_sn1.h> #include <asm/sn/sn_cpuid.h> diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/mmzone_sn1.h linux/include/asm-ia64/sn/mmzone_sn1.h --- v2.4.3/linux/include/asm-ia64/sn/mmzone_sn1.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/mmzone_sn1.h Thu Apr 5 12:51:47 2001 @@ -1,12 +1,11 @@ #ifndef _ASM_IA64_MMZONE_SN1_H #define _ASM_IA64_MMZONE_SN1_H +#include <linux/config.h> + /* * Copyright, 2000, Silicon Graphics, sprasad@engr.sgi.com */ - -#include <linux/config.h> - /* Maximum configuration supported by SNIA hardware. There are other * restrictions that may limit us to a smaller max configuration. */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/module.h linux/include/asm-ia64/sn/module.h --- v2.4.3/linux/include/asm-ia64/sn/module.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/module.h Thu Apr 5 12:51:47 2001 @@ -15,6 +15,7 @@ #endif #include <linux/config.h> + #include <asm/sn/systeminfo.h> #include <asm/sn/klconfig.h> #include <asm/sn/ksys/elsc.h> @@ -178,22 +179,24 @@ int disable_alert; int count_down; + + /* System serial number info (used by SN1) */ + char sys_snum[MAX_SERIAL_NUM_SIZE]; + int sys_snum_valid; }; /* module.c */ extern module_t *modules[MODULE_MAX]; /* Indexed by cmoduleid_t */ extern int nummodules; -#ifndef CONFIG_IA64_SGI_IO -/* Clashes with LINUX stuff */ -extern void module_init(void); -#endif extern module_t *module_lookup(moduleid_t id); extern elsc_t *get_elsc(void); extern int get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info); +extern int get_kmod_sys_snum(cmoduleid_t cmod, + char *snum); extern void format_module_id(char *buffer, moduleid_t m, int fmt); extern int parse_module_id(char *buffer); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/nodemask.h linux/include/asm-ia64/sn/nodemask.h --- v2.4.3/linux/include/asm-ia64/sn/nodemask.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/nodemask.h Thu Apr 5 12:51:47 2001 @@ -13,6 +13,7 @@ #if defined(__KERNEL__) || defined(_KMEMUSER) #include <linux/config.h> + #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC #include <asm/sn/sn1/arch.h> /* needed for MAX_COMPACT_NODES */ #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/nodepda.h linux/include/asm-ia64/sn/nodepda.h --- v2.4.3/linux/include/asm-ia64/sn/nodepda.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/nodepda.h Thu Apr 5 12:51:47 2001 @@ -15,11 +15,13 @@ #endif #include <linux/config.h> + #include <asm/sn/agent.h> #include <asm/sn/intr.h> #include <asm/sn/router.h> +#include <asm/sn/synergy.h> /* #include <SN/klkernvars.h> */ -#ifdef IRIX +#ifdef LATER typedef struct module_s module_t; /* Avoids sys/SN/module.h */ #else #include <asm/sn/module.h> @@ -54,6 +56,10 @@ struct ptpool_s; +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) +struct synergy_perf_s; +#endif + /* * Node-specific data structure. @@ -67,7 +73,8 @@ */ -#ifndef CONFIG_IA64_SGI_IO + +#ifdef LATER /* * The following structure is contained in the nodepda & contains * a lock & queue-head for sanon pages that belong to the node. @@ -78,9 +85,6 @@ plist_t sal_listhead; } sanon_list_head_t; #endif - - - struct nodepda_s { #ifdef NUMA_BASE @@ -133,7 +137,7 @@ * Each node gets its own syswait counter to remove contention * on the global one. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER struct syswait syswait; #endif @@ -141,7 +145,7 @@ /* * Node-specific Zone structures. */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER zoneset_element_t node_zones; pg_data_t node_pg_data; /* VM page data structures */ plist_t error_discard_plist; @@ -154,7 +158,7 @@ /* Information needed for SN Hub chip interrupt handling. */ subnode_pda_t snpda[NUM_SUBNODES]; /* Distributed kernel support */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER kern_vars_t kern_vars; #endif /* Vector operation support */ @@ -173,6 +177,17 @@ nodepda_router_info_t *npda_rip_first; nodepda_router_info_t **npda_rip_last; int dependent_routers; + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + int synergy_perf_enabled; + int synergy_perf_freq; + spinlock_t synergy_perf_lock; + uint64_t synergy_inactive_intervals; + uint64_t synergy_active_intervals; + struct synergy_perf_s *synergy_perf_data; + struct synergy_perf_s *synergy_perf_first; /* reporting consistency .. */ +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + devfs_handle_t xbow_vhdl; nasid_t xbow_peer; /* NASID of our peer hub on xbow */ struct semaphore xbow_sema; /* Sema for xbow synchronization */ @@ -189,13 +204,13 @@ char ni_error_print; /* For printing ni error state * only once during system panic */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER md_perf_monitor_t node_md_perfmon; hubstat_t hubstats; int hubticks; - int huberror_ticks; sbe_info_t *sbe_info; /* ECC single-bit error statistics */ -#endif /* !CONFIG_IA64_SGI_IO */ +#endif /* LATER */ + int huberror_ticks; router_queue_t *visited_router_q; router_queue_t *bfs_router_q; @@ -218,11 +233,9 @@ void *pdinfo; /* Platform-dependent per-node info */ uint64_t *dump_stack; /* Dump stack during nmi handling */ int dump_count; /* To allow only one cpu-per-node */ -#if defined BRINGUP -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER io_perf_monitor_t node_io_perfmon; #endif -#endif /* * Each node gets its own pdcount counter to remove contention @@ -235,7 +248,7 @@ void *cached_global_pool; /* pointer to cached vmpool */ #endif /* NUMA_BASE */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER sanon_list_head_t sanon_list_head; /* head for sanon pages */ #endif #ifdef NUMA_BASE @@ -246,7 +259,7 @@ * The BTEs on this node are shared by the local cpus */ #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER bteinfo_t *node_bte_info[BTES_PER_NODE]; #endif #endif @@ -273,7 +286,7 @@ * SUBNODEPDA(x,s) -> to access subnode PDA for cnodeid/slice 'x' */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER #define nodepda private.p_nodepda /* Ptr to this node's PDA */ #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC #define subnodepda private.p_subnodepda /* Ptr to this node's subnode PDA */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h --- v2.4.3/linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pci/pci_bus_cvlink.h Thu Apr 5 12:51:47 2001 @@ -26,4 +26,23 @@ int isa64; }; +struct sn1_dma_maps_s{ + struct pcibr_dmamap_s dma_map; + dma_addr_t dma_addr; +}; + +struct ioports_to_tlbs_s { + unsigned long p:1, + rv_1:1, + ma:3, + a:1, + d:1, + pl:2, + ar:3, + ppn:38, + rv_2:2, + ed:1, + ig:11; +}; + #endif /* _ASM_SN_PCI_CVLINK_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pciba.h linux/include/asm-ia64/sn/pci/pciba.h --- v2.4.3/linux/include/asm-ia64/sn/pci/pciba.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ia64/sn/pci/pciba.h Thu Apr 5 12:51:47 2001 @@ -0,0 +1,103 @@ +/* $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 + */ +#ifndef _ASM_SN_PCI_PCIBA_H +#define _ASM_SN_PCI_PCIBA_H + +/* + * These are all the HACKS from ioccom.h .. + */ +#define IOCPARM_MASK 0xff /* parameters must be < 256 bytes */ +#define IOC_VOID 0x20000000 /* no parameters */ + +/* + * The above needs to be modified and follow LINUX ... + */ + +/* /hw/.../pci/[slot]/config accepts ioctls to read + * and write specific registers as follows: + * + * "t" is the native type (char, short, uint32, uint64) + * to read from CFG space; results will be arranged in + * byte significance (ie. first byte from PCI is lowest + * or last byte in result). + * + * "r" is the byte offset in PCI CFG space of the first + * byte of the register (it's least significant byte, + * in the little-endian PCI numbering). This can actually + * be as much as 16 bits wide, and is intended to match + * the layout of a "Type 1 Configuration Space" address: + * the register number in the low eight bits, then three + * bits for the function number and five bits for the + * slot number. + */ +#define PCIIOCCFGRD(t,r) _IOR(0,(r),t) +#define PCIIOCCFGWR(t,r) _IOW(0,(r),t) + +/* Some common config register access commands. + * Use these as examples of how to construct + * values for other registers you want to access. + */ + +/* PCIIOCGETID: arg is ptr to 32-bit int, + * returns the 32-bit ID value with VENDOR + * in the bottom 16 bits and DEVICE in the top. + */ +#define PCIIOCGETID PCIIOCCFGRD(uint32_t,PCI_CFG_VENDOR_ID) + +/* PCIIOCSETCMD: arg is ptr to a 16-bit short, + * which will be written to the CMD register. + */ +#define PCIIOCSETCMD PCIIOCCFGWR(uint16_t,PCI_CFG_COMMAND) + +/* PCIIOCGETREV: arg is ptr to an 8-bit char, + * which will get the 8-bit revision number. + */ +#define PCIIOCGETREV PCIIOCCFGRD(uint8_t,PCI_CFG_REV_ID) + +/* PCIIOCGETHTYPE: arg is ptr to an 8-bit char, + * which will get the 8-bit header type. + */ +#define PCIIOCGETHTYPE PCIIOCCFGRD(uint8_t,PCI_CFG_HEADER_TYPE) + +/* PCIIOCGETBASE(n): arg is ptr to a 32-bit int, + * which will get the value of the BASE<n> register. + */ +#define PCIIOCGETBASE(n) PCIIOCCFGRD(uint32_t,PCI_CFG_BASE_ADDR(n)) + +/* /hw/.../pci/[slot]/intr accepts an ioctl to + * set up user level interrupt handling as follows: + * + * "n" is a bitmap of which of the four PCI interrupt + * lines are of interest, using PCIIO_INTR_LINE_[ABCD]. + */ +#define PCIIOCSETULI(n) _IOWR(1,n,struct uliargs) +#if _KERNEL +#define PCIIOCSETULI32(n) _IOWR(1,n,struct uliargs32) +#endif + +/* /hw/.../pci/[slot]/dma accepts ioctls to allocate + * and free physical memory for use in user-triggered + * DMA operations. + */ +#define PCIIOCDMAALLOC _IOWR(0,1,uint64_t) +#define PCIIOCDMAFREE _IOW(0,1,uint64_t) + +/* The parameter for PCIIOCDMAALLOC needs to contain + * both the size of the request and the flag values + * to be used in setting up the DMA. + * + * Any flags normally useful in pciio_dmamap + * or pciio_dmatrans function calls can6 be used here. + */ +#define PCIIOCDMAALLOC_REQUEST_PACK(flags,size) \ + ((((uint64_t)(flags))<<32)| \ + (((uint64_t)(size))&0xFFFFFFFF)) + +#endif /* _ASM_SN_PCI_PCIBA_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pcibr.h linux/include/asm-ia64/sn/pci/pcibr.h --- v2.4.3/linux/include/asm-ia64/sn/pci/pcibr.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pci/pcibr.h Thu Apr 5 12:51:47 2001 @@ -143,6 +143,14 @@ extern void pcibr_dmamap_done(pcibr_dmamap_t dmamap); +/* + * pcibr_get_dmatrans_node() will return the compact node id to which + * all 32-bit Direct Mapping memory accesses will be directed. + * (This node id can be different for each PCI bus.) + */ + +extern cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl); + extern iopaddr_t pcibr_dmatrans_addr(devfs_handle_t dev, device_desc_t dev_desc, paddr_t paddr, @@ -215,10 +223,6 @@ pciio_space_t *spacep, iopaddr_t *addrp); -extern int pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1); - extern int pcibr_wrb_flush(devfs_handle_t pconn_vhdl); extern int pcibr_rrb_check(devfs_handle_t pconn_vhdl, int *count_vchan0, @@ -241,7 +245,7 @@ void pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_f *func); -extern void pcibr_device_unregister(devfs_handle_t); +extern int pcibr_device_unregister(devfs_handle_t); extern int pcibr_dma_enabled(devfs_handle_t); /* * Bridge-specific flags that can be set via pcibr_device_flags_set @@ -337,7 +341,7 @@ extern void pcibr_hints_fix_rrbs(devfs_handle_t); extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); +extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); extern void pcibr_hints_handsoff(devfs_handle_t); typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t); @@ -353,8 +357,104 @@ #define PCIBR 'p' #define _PCIBR(x) ((PCIBR << 8) | (x)) -#define PCIBR_SLOT_POWERUP _PCIBR(1) -#define PCIBR_SLOT_SHUTDOWN _PCIBR(2) -#define PCIBR_SLOT_INQUIRY _PCIBR(3) +#define PCIBR_SLOT_STARTUP _PCIBR(1) +#define PCIBR_SLOT_SHUTDOWN _PCIBR(2) +#define PCIBR_SLOT_QUERY _PCIBR(3) + +/* + * Bit defintions for variable slot_status in struct + * pcibr_soft_slot_s. They are here so that both + * the pcibr driver and the pciconfig command can + * reference them. + */ +#define SLOT_STARTUP_CMPLT 0x01 +#define SLOT_STARTUP_INCMPLT 0x02 +#define SLOT_SHUTDOWN_CMPLT 0x04 +#define SLOT_SHUTDOWN_INCMPLT 0x08 +#define SLOT_POWER_UP 0x10 +#define SLOT_POWER_DOWN 0x20 +#define SLOT_IS_SYS_CRITICAL 0x40 + +#define SLOT_STATUS_MASK (SLOT_STARTUP_CMPLT | SLOT_STARTUP_INCMPLT | \ + SLOT_SHUTDOWN_CMPLT | SLOT_SHUTDOWN_INCMPLT) +#define SLOT_POWER_MASK (SLOT_POWER_UP | SLOT_POWER_DOWN) + +/* + * Bit definitions for variable resp_f_staus. + * They are here so that both the pcibr driver + * and the pciconfig command can reference them. + */ +#define FUNC_IS_VALID 0x01 +#define FUNC_IS_SYS_CRITICAL 0x02 + +/* + * Structures for requesting PCI bridge information and receiving a response + */ +typedef struct pcibr_slot_info_req_s *pcibr_slot_info_req_t; +typedef struct pcibr_slot_info_resp_s *pcibr_slot_info_resp_t; +typedef struct pcibr_slot_func_info_resp_s *pcibr_slot_func_info_resp_t; + +struct pcibr_slot_info_req_s { + int req_slot; + pcibr_slot_info_resp_t req_respp; + int req_size; +}; + +struct pcibr_slot_info_resp_s { + int resp_has_host; + char resp_host_slot; + devfs_handle_t resp_slot_conn; + char resp_slot_conn_name[MAXDEVNAME]; + int resp_slot_status; + int resp_l1_bus_num; + int resp_bss_ninfo; + char resp_bss_devio_bssd_space[16]; + iopaddr_t resp_bss_devio_bssd_base; + bridgereg_t resp_bss_device; + int resp_bss_pmu_uctr; + int resp_bss_d32_uctr; + int resp_bss_d64_uctr; + iopaddr_t resp_bss_d64_base; + unsigned resp_bss_d64_flags; + iopaddr_t resp_bss_d32_base; + unsigned resp_bss_d32_flags; + int resp_bss_ext_ates_active; + volatile unsigned *resp_bss_cmd_pointer; + unsigned resp_bss_cmd_shadow; + int resp_bs_rrb_valid; + int resp_bs_rrb_valid_v; + int resp_bs_rrb_res; + bridgereg_t resp_b_resp; + bridgereg_t resp_b_int_device; + bridgereg_t resp_b_int_enable; + bridgereg_t resp_b_int_host; + + struct pcibr_slot_func_info_resp_s { + int resp_f_status; + char resp_f_slot_name[MAXDEVNAME]; + char resp_f_bus; + char resp_f_slot; + char resp_f_func; + char resp_f_master_name[MAXDEVNAME]; + void *resp_f_pops; + error_handler_f *resp_f_efunc; + error_handler_arg_t resp_f_einfo; + int resp_f_vendor; + int resp_f_device; + + struct { + char resp_w_space[16]; + iopaddr_t resp_w_base; + size_t resp_w_size; + } resp_f_window[6]; + + unsigned resp_f_rbase; + unsigned resp_f_rsize; + int resp_f_ibit[4]; + int resp_f_att_det_error; + + } resp_func[8]; + +}; #endif /* _ASM_SN_PCI_PCIBR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pcibr_private.h linux/include/asm-ia64/sn/pci/pcibr_private.h --- v2.4.3/linux/include/asm-ia64/sn/pci/pcibr_private.h Tue Mar 6 19:44:34 2001 +++ linux/include/asm-ia64/sn/pci/pcibr_private.h Thu Apr 5 12:51:47 2001 @@ -17,6 +17,7 @@ */ #include <asm/sn/pci/pciio_private.h> +#include <asm/sn/ksys/l1.h> /* * convenience typedefs @@ -31,6 +32,7 @@ typedef struct pcibr_hints_s *pcibr_hints_t; typedef struct pcibr_intr_list_s *pcibr_intr_list_t; typedef struct pcibr_intr_wrap_s *pcibr_intr_wrap_t; +typedef struct pcibr_intr_cbuf_s *pcibr_intr_cbuf_t; /* * Bridge sets up PIO using this information. @@ -50,7 +52,7 @@ xtalk_piomap_t bp_xtalk_pio; /* corresponding xtalk resource */ pcibr_piomap_t bp_next; /* Next piomap on the list */ pcibr_soft_t bp_soft; /* backpointer to bridge soft data */ - int bp_toc[1]; /* PCI timeout counter */ + atomic_t bp_toc[1]; /* PCI timeout counter */ }; @@ -77,6 +79,18 @@ bridge_ate_t bd_ate_prime; /* value of 1st ATE written */ }; +#define IBUFSIZE 5 /* size of circular buffer (holds 4) */ + +/* + * Circular buffer used for interrupt processing + */ +struct pcibr_intr_cbuf_s { + spinlock_t ib_lock; /* cbuf 'put' lock */ + int ib_in; /* index of next free entry */ + int ib_out; /* index of next full entry */ + pcibr_intr_wrap_t ib_cbuf[IBUFSIZE]; /* circular buffer of wrap */ +}; + /* * Bridge sets up interrupts using this information. */ @@ -94,6 +108,7 @@ #define bi_cpu bi_pi.pi_cpu /* cpu assigned. */ unsigned bi_ibits; /* which Bridge interrupt bit(s) */ pcibr_soft_t bi_soft; /* shortcut to soft info */ + struct pcibr_intr_cbuf_s bi_ibuf; /* circular buffer of wrap ptrs */ }; /* @@ -121,6 +136,7 @@ /* pcibr-specific connection state */ int f_ibit[4]; /* Bridge bit for each INTx */ pcibr_piomap_t f_piomap; + int f_att_det_error; }; /* ===================================================================== @@ -139,8 +155,11 @@ struct pcibr_intr_wrap_s { pcibr_soft_t iw_soft; /* which bridge */ volatile bridgereg_t *iw_stat; /* ptr to b_int_status */ - bridgereg_t iw_intr; /* bits in b_int_status */ + bridgereg_t iw_intr; /* bit in b_int_status */ pcibr_intr_list_t iw_list; /* ghostbusters! */ + int iw_hdlrcnt; /* running handler count */ + int iw_shared; /* if Bridge bit is shared */ + int iw_connected; /* if already connected */ }; #define PCIBR_ISR_ERR_START 8 @@ -175,11 +194,14 @@ unsigned bs_dma_flags; /* revision-implied DMA flags */ + l1sc_t *bs_l1sc; /* io brick l1 system cntr */ + moduleid_t bs_moduleid; /* io brick moduleid */ + /* * Lock used primarily to get mutual exclusion while managing any * bridge resources.. */ - lock_t bs_lock; + spinlock_t bs_lock; devfs_handle_t bs_noslot_conn; /* NO-SLOT connection point */ pcibr_info_t bs_noslot_info; @@ -199,6 +221,9 @@ int has_host; pciio_slot_t host_slot; devfs_handle_t slot_conn; + + int slot_status; + /* Potentially several connection points * for this slot. bss_ninfo is how many, * and bss_infos is a pointer to @@ -265,7 +290,7 @@ /* Shadow information used for implementing * Bridge Hardware WAR #484930 */ - int bss_ext_ates_active; + atomic_t bss_ext_ates_active; volatile unsigned *bss_cmd_pointer; unsigned bss_cmd_shadow; @@ -295,13 +320,10 @@ */ xtalk_intr_t bsi_xtalk_intr; /* - * We do not like sharing PCI interrrupt lines - * between devices, but the Origin 200 PCI - * layout forces us to do so. + * A wrapper structure is associated with each + * Bridge interrupt bit. */ - pcibr_intr_list_t bsi_pcibr_intr_list; - pcibr_intr_wrap_t bsi_pcibr_intr_wrap; - int bsi_pcibr_wrap_set; + struct pcibr_intr_wrap_s bsi_pcibr_intr_wrap; } bs_intr[8]; @@ -325,7 +347,7 @@ */ struct br_errintr_info { int bserr_toutcnt; -#ifdef IRIX +#ifdef LATER toid_t bserr_toutid; /* Timeout started by errintr */ #endif iopaddr_t bserr_addr; /* Address where error occurred */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pciio.h linux/include/asm-ia64/sn/pci/pciio.h --- v2.4.3/linux/include/asm-ia64/sn/pci/pciio.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pci/pciio.h Thu Apr 5 12:51:47 2001 @@ -35,15 +35,9 @@ #define PCIIO_DEVICE_ID_NONE -1 -#ifdef colin -typedef char pciio_bus_t; /* PCI bus number (0..255) */ -typedef char pciio_slot_t; /* PCI slot number (0..31, 255) */ -typedef char pciio_function_t; /* PCI func number (0..7, 255) */ -#else typedef uint8_t pciio_bus_t; /* PCI bus number (0..255) */ typedef uint8_t pciio_slot_t; /* PCI slot number (0..31, 255) */ typedef uint8_t pciio_function_t; /* PCI func number (0..7, 255) */ -#endif #define PCIIO_SLOTS ((pciio_slot_t)32) #define PCIIO_FUNCS ((pciio_function_t)8) @@ -446,6 +440,24 @@ pciio_space_t *spacep, iopaddr_t *addrp); +typedef void +pciio_driver_reg_callback_f (devfs_handle_t conn, + int key1, + int key2, + int error); + +typedef void +pciio_driver_unreg_callback_f (devfs_handle_t conn, /* pci connection point */ + int key1, + int key2, + int error); + +typedef int +pciio_device_unregister_f (devfs_handle_t conn); + +typedef int +pciio_dma_enabled_f (devfs_handle_t conn); + /* * Adapters that provide a PCI interface adhere to this software interface. */ @@ -491,6 +503,12 @@ /* Error handling interface */ pciio_error_devenable_f *error_devenable; pciio_error_extract_f *error_extract; + + /* Callback support */ + pciio_driver_reg_callback_f *driver_reg_callback; + pciio_driver_unreg_callback_f *driver_unreg_callback; + pciio_device_unregister_f *device_unregister; + pciio_dma_enabled_f *dma_enabled; } pciio_provider_t; /* PCI devices use these standard PCI provider interfaces */ @@ -540,13 +558,8 @@ #define PCIIO_WIDGETDEV_SLOT_MASK 0x1f #define PCIIO_WIDGETDEV_FUNC_MASK 0x7 -#ifdef IRIX -#define pciio_widgetdev_create(slot,func) \ - ((slot) << PCIIO_WIDGETDEV_SLOT_SHFT + (func)) -#else #define pciio_widgetdev_create(slot,func) \ (((slot) << PCIIO_WIDGETDEV_SLOT_SHFT) + (func)) -#endif #define pciio_widgetdev_slot_get(wdev) \ (((wdev) >> PCIIO_WIDGETDEV_SLOT_SHFT) & PCIIO_WIDGETDEV_SLOT_MASK) @@ -612,8 +625,14 @@ pciio_info_t pciio_info); /* details about conn point */ -extern int pciio_device_attach(devfs_handle_t pcicard); /* vertex created by pciio_device_register */ -extern int pciio_device_detach(devfs_handle_t pcicard); /* vertex created by pciio_device_register */ +extern int +pciio_device_attach( + devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + int drv_flags); +extern int +pciio_device_detach( + devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + int drv_flags); /* * Generic PCI interface, for use with all PCI providers @@ -632,7 +651,7 @@ extern ulong pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap); extern caddr_t pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap); -#ifdef IRIX +#ifdef LATER #ifdef USE_PCI_PIO extern uint8_t pciio_pio_read8(volatile uint8_t *addr); extern uint16_t pciio_pio_read16(volatile uint16_t *addr); @@ -676,7 +695,7 @@ *addr = val; } #endif /* USE_PCI_PIO */ -#endif +#endif /* LATER */ /* Generic PCI dma interfaces */ extern devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pci/pciio_private.h linux/include/asm-ia64/sn/pci/pciio_private.h --- v2.4.3/linux/include/asm-ia64/sn/pci/pciio_private.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pci/pciio_private.h Thu Apr 5 12:51:47 2001 @@ -10,10 +10,6 @@ #ifndef _ASM_SN_PCI_PCIIO_PRIVATE_H #define _ASM_SN_PCI_PCIIO_PRIVATE_H -#ifdef colin -#include <ksys/xthread.h> -#endif - /* * pciio_private.h -- private definitions for pciio * PCI drivers should NOT include this file. @@ -54,12 +50,12 @@ pciio_intr_line_t pi_lines; /* which interrupt line(s) */ intr_func_t pi_func; /* handler function (when connected) */ intr_arg_t pi_arg; /* handler parameter (when connected) */ -#ifdef IRIX +#ifdef LATER thd_int_t pi_tinfo; /* Thread info (when connected) */ #endif cpuid_t pi_mustruncpu; /* Where we must run. */ - int pi_irq; /* IRQ assigned */ - int pi_cpu; /* cpu assigned */ + int pi_irq; /* IRQ assigned */ + int pi_cpu; /* cpu assigned */ }; /* PCIIO_INTR (pi_flags) flags */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/pio.h linux/include/asm-ia64/sn/pio.h --- v2.4.3/linux/include/asm-ia64/sn/pio.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pio.h Thu Apr 5 12:51:47 2001 @@ -33,7 +33,7 @@ typedef struct piomap { uint pio_bus; uint pio_adap; -#ifdef IRIX +#ifdef LATER iospace_t pio_iospace; #endif int pio_flag; @@ -41,7 +41,7 @@ char pio_name[7]; /* to identify the mapped device */ struct piomap *pio_next; /* dlist to link active piomap's */ struct piomap *pio_prev; /* for debug and error reporting */ -#ifdef IRIX +#ifdef LATER void (*pio_errfunc)(); /* Pointer to an error function */ /* Used only for piomaps allocated * in user level vme driver */ @@ -50,6 +50,10 @@ iobush_t pio_bushandle; /* bus-level handle */ } piomap_t; +#define pio_type pio_iospace.ios_type +#define pio_iopaddr pio_iospace.ios_iopaddr +#define pio_size pio_iospace.ios_size +#define pio_vaddr pio_iospace.ios_vaddr /* Macro to get/set PIO error function */ #define pio_seterrf(p,f) (p)->pio_errfunc = (f) @@ -64,7 +68,7 @@ * pio_mapfree() - frees the mapping as specified in the piomap handle. * pio_mapaddr() - returns the kv address that maps to piomap'ed io address. */ -#ifdef IRIX +#ifdef LATER extern piomap_t *pio_mapalloc(uint,uint,iospace_t*,int,char*); extern void pio_mapfree(piomap_t*); extern caddr_t pio_mapaddr(piomap_t*,iopaddr_t); @@ -101,7 +105,7 @@ extern void andb_rmw(volatile void*, unsigned int); extern void andh_rmw(volatile void*, unsigned int); extern void andw_rmw(volatile void*, unsigned int); -#endif /* IRIX */ +#endif /* LATER */ /* diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/router.h linux/include/asm-ia64/sn/router.h --- v2.4.3/linux/include/asm-ia64/sn/router.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/router.h Thu Apr 5 12:51:47 2001 @@ -11,6 +11,7 @@ #define _ASM_SN_ROUTER_H #include <linux/config.h> + #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC #include <asm/sn/sn1/router.h> #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sgi.h linux/include/asm-ia64/sn/sgi.h --- v2.4.3/linux/include/asm-ia64/sn/sgi.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/sgi.h Thu Apr 5 12:51:47 2001 @@ -13,6 +13,7 @@ #define _ASM_SN_SGI_H #include <linux/config.h> + #include <asm/sn/types.h> #include <asm/uaccess.h> /* for copy_??_user */ #include <linux/mm.h> @@ -121,18 +122,6 @@ GRAPH_IN_USE /* 7 */ } graph_error_t; -#define SV_FIFO 0x0 /* sv_t is FIFO type */ -#define SV_LIFO 0x2 /* sv_t is LIFO type */ -#define SV_PRIO 0x4 /* sv_t is PRIO type */ -#define SV_KEYED 0x6 /* sv_t is KEYED type */ -#define SV_DEFAULT SV_FIFO - - -#define MUTEX_DEFAULT 0x0 /* needed by mutex_init() calls */ -#define PZERO 25 /* needed by mutex_lock(), sv_wait() - * psema() calls */ - -#define sema_t uint64_t /* FIXME */ #define KM_SLEEP 0x0000 #define KM_NOSLEEP 0x0001 /* needed by kmem_alloc_node(), kmem_zalloc() * calls */ @@ -140,10 +129,6 @@ * calls */ #define XG_WIDGET_PART_NUM 0xC102 /* KONA/xt_regs.h XG_XT_PART_NUM_VALUE */ -#ifndef K1BASE -#define K1BASE 0xA0000000 -#endif - #ifndef TO_PHYS_MASK #define TO_PHYS_MASK 0x0000000fffffffff #endif @@ -171,8 +156,6 @@ #define _PAGESZ 4096 #endif -typedef uint64_t k_machreg_t; /* needed by cmn_err.h */ - typedef uint64_t mrlock_t; /* needed by devsupport.c */ #define HUB_PIO_CONVEYOR 0x1 @@ -188,44 +171,64 @@ #define POFFMASK (NBPP - 1) #define poff(X) ((__psunsigned_t)(X) & POFFMASK) -#define initnsema(a,b,c) sema_init(a,b) - #define BZERO(a,b) memset(a, 0, b) -#define kern_malloc(x) kmalloc(x, GFP_KERNEL) -#define kern_free(x) kfree(x) +#define kern_malloc(x) kmalloc(x, GFP_KERNEL) +#define kern_free(x) kfree(x) typedef cpuid_t cpu_cookie_t; #define CPU_NONE -1 +/* + * mutext support mapping + */ + +#define mutex_spinlock_init(s) spin_lock_init(s) +inline static unsigned long +mutex_spinlock(spinlock_t *sem) { + unsigned long flags = 0; +// spin_lock_irqsave(sem, flags); + spin_lock(sem); + return(flags); +} +// #define mutex_spinunlock(s,t) spin_unlock_irqrestore(s,t) +#define mutex_spinunlock(s,t) spin_unlock(s) + + +#define mutex_t struct semaphore +#define mutex_init(s) init_MUTEX(s) +#define mutex_init_locked(s) init_MUTEX_LOCKED(s) +#define mutex_lock(s) down(s) +#define mutex_unlock(s) up(s) + +#define io_splock(s) mutex_spinlock(s) +#define io_spunlock(s,t) spin_unlock(s) + +#define spin_lock_destroy(s) #if defined(DISABLE_ASSERT) #define ASSERT(expr) #define ASSERT_ALWAYS(expr) #else -#define ASSERT(expr) \ +#define ASSERT(expr) do { \ if(!(expr)) { \ printk( "Assertion [%s] failed! %s:%s(line=%d)\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ panic("Assertion panic\n"); \ - } + } } while(0) -#define ASSERT_ALWAYS(expr) \ +#define ASSERT_ALWAYS(expr) do {\ if(!(expr)) { \ printk( "Assertion [%s] failed! %s:%s(line=%d)\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ panic("Assertion always panic\n"); \ - } + } } while(0) #endif /* DISABLE_ASSERT */ -/* These are defined as cmn_err() replacements */ -#define PRINT_WARNING(x...) { printk("WARNING : "); printk(x); } -#define PRINT_NOTICE(x...) { printk("NOTICE : "); printk(x); } -#define PRINT_ALERT(x...) { printk("ALERT : "); printk(x); } +#define PRINT_WARNING(x...) do { printk("WARNING : "); printk(x); } while(0) +#define PRINT_NOTICE(x...) do { printk("NOTICE : "); printk(x); } while(0) +#define PRINT_ALERT(x...) do { printk("ALERT : "); printk(x); } while(0) #define PRINT_PANIC panic - -#define mutex_t int -#define spinlock_init(x,name) mutex_init(x, MUTEX_DEFAULT, name); #ifdef CONFIG_SMP #define cpu_enabled(cpu) (test_bit(cpu, &cpu_online_map)) diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/slotnum.h linux/include/asm-ia64/sn/slotnum.h --- v2.4.3/linux/include/asm-ia64/sn/slotnum.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/slotnum.h Thu Apr 5 12:51:47 2001 @@ -10,9 +10,10 @@ #ifndef _ASM_SN_SLOTNUM_H #define _ASM_SN_SLOTNUM_H +#include <linux/config.h> + typedef unsigned char slotid_t; -#include <linux/config.h> #if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/sn1/slotnum.h> #else diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/addrs.h linux/include/asm-ia64/sn/sn1/addrs.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/addrs.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/addrs.h Thu Apr 5 12:51:47 2001 @@ -43,22 +43,19 @@ #if defined(_RUN_UNCACHED) #define CAC_BASE 0x9600000000000000 #else +#ifndef __ia64 #define CAC_BASE 0xa800000000000000 +#else +#define CAC_BASE 0xe000000000000000 +#endif #endif -#ifdef Colin -#define HSPEC_BASE 0x9000000000000000 -#define IO_BASE 0x9200000000000000 -#define MSPEC_BASE 0x9400000000000000 -#define UNCAC_BASE 0x9600000000000000 -#else #define HSPEC_BASE 0xc0000b0000000000 #define HSPEC_SWIZ_BASE 0xc000030000000000 #define IO_BASE 0xc0000a0000000000 #define IO_SWIZ_BASE 0xc000020000000000 #define MSPEC_BASE 0xc000000000000000 #define UNCAC_BASE 0xc000000000000000 -#endif #define TO_PHYS(x) ( ((x) & TO_PHYS_MASK)) #define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK)) diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/bedrock.h linux/include/asm-ia64/sn/sn1/bedrock.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/bedrock.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/sn1/bedrock.h Thu Apr 5 12:51:47 2001 @@ -11,6 +11,8 @@ #ifndef _ASM_SN_SN1_BEDROCK_H #define _ASM_SN_SN1_BEDROCK_H +#include <linux/config.h> + /* The secret password; used to release protection */ #define HUB_PASSWORD 0x53474972756c6573ull @@ -22,7 +24,6 @@ #define MAX_HUB_PATH 80 -#include <linux/config.h> #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) #include <asm/sn/arch.h> #include <asm/sn/sn1/addrs.h> diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/hubio_next.h linux/include/asm-ia64/sn/sn1/hubio_next.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/hubio_next.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/hubio_next.h Thu Apr 5 12:51:47 2001 @@ -43,6 +43,8 @@ #define IIO_IOPRB_0 IIO_IPRB0 #define IIO_PRTE_0 IIO_IPRTE0 /* PIO Read address table entry 0 */ #define IIO_PRTE(_x) (IIO_PRTE_0 + (8 * (_x))) +#define IIO_NUM_IPRBS (9) +#define IIO_WIDPRTE(x) IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */ #define IIO_LLP_CSR_IS_UP 0x00002000 #define IIO_LLP_CSR_LLP_STAT_MASK 0x00003000 @@ -192,6 +194,21 @@ #define HUBII_XBOW_CREDIT 3 #define HUBII_XBOW_REV2_CREDIT 4 +/* + * Number of credits that xtalk devices should use when communicating + * with a Bedrock (depth of Bedrock's queue). + */ +#define HUB_CREDIT 4 + +/* + * Some IIO_PRB fields + */ +#define IIO_PRB_MULTI_ERR (1LL << 63) +#define IIO_PRB_SPUR_RD (1LL << 51) +#define IIO_PRB_SPUR_WR (1LL << 50) +#define IIO_PRB_RD_TO (1LL << 49) +#define IIO_PRB_ERROR (1LL << 48) + /************************************************************************* Some of the IIO field masks and shifts are defined here. @@ -245,6 +262,29 @@ #define IBCT_ZFIL_MODE (0x1 << 0) /* + * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2) + */ +#define IIEPH1_VALID (1 << 44) +#define IIEPH1_OVERRUN (1 << 40) +#define IIEPH1_ERR_TYPE_SHFT 32 +#define IIEPH1_ERR_TYPE_MASK 0xf +#define IIEPH1_SOURCE_SHFT 20 +#define IIEPH1_SOURCE_MASK 11 +#define IIEPH1_SUPPL_SHFT 8 +#define IIEPH1_SUPPL_MASK 11 +#define IIEPH1_CMD_SHFT 0 +#define IIEPH1_CMD_MASK 7 + +#define IIEPH2_TAIL (1 << 40) +#define IIEPH2_ADDRESS_SHFT 0 +#define IIEPH2_ADDRESS_MASK 38 + +#define IIEPH1_ERR_SHORT_REQ 2 +#define IIEPH1_ERR_SHORT_REPLY 3 +#define IIEPH1_ERR_LONG_REQ 4 +#define IIEPH1_ERR_LONG_REPLY 5 + +/* * IO Error Clear register bit field definitions */ #define IECLR_PI1_FWD_INT (1 << 31) /* clear PI1_FORWARD_INT in iidsr */ @@ -363,6 +403,10 @@ /* A few more #defines for backwards compatibility */ #define iprb_t ii_iprb0_u_t #define iprb_regval ii_iprb0_regval +#define iprb_mult_err ii_iprb0_fld_s.i_mult_err +#define iprb_spur_rd ii_iprb0_fld_s.i_spur_rd +#define iprb_spur_wr ii_iprb0_fld_s.i_spur_wr +#define iprb_rd_to ii_iprb0_fld_s.i_rd_to #define iprb_ovflow ii_iprb0_fld_s.i_of_cnt #define iprb_error ii_iprb0_fld_s.i_error #define iprb_ff ii_iprb0_fld_s.i_f @@ -385,7 +429,6 @@ #define IO_PERF_SETS 32 -#ifdef BRINGUP #if __KERNEL__ #if _LANGUAGE_C /* XXX moved over from SN/SN0/hubio.h -- each should be checked for SN1 */ @@ -646,6 +689,11 @@ device_desc_t dev_desc, /* device descriptor */ devfs_handle_t owner_dev); /* owner of this interrupt */ +extern hub_intr_t +hub_intr_alloc_nothd(devfs_handle_t dev, /* which device */ + device_desc_t dev_desc, /* device descriptor */ + devfs_handle_t owner_dev); /* owner of this interrupt */ + extern void hub_intr_free(hub_intr_t intr_hdl); @@ -710,5 +758,4 @@ #endif /* _LANGUAGE_C */ #endif /* _KERNEL */ -#endif /* BRINGUP */ #endif /* _ASM_SN_SN1_HUBIO_NEXT_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/hubpi_next.h linux/include/asm-ia64/sn/sn1/hubpi_next.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/hubpi_next.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/hubpi_next.h Thu Apr 5 12:51:47 2001 @@ -274,7 +274,9 @@ * The following three macros define all possible error int pends. */ -#define PI_FATAL_ERR_CPU_A (PI_ERR_SYSAD_BAD_DATA_A | \ +#define PI_FATAL_ERR_CPU_A (PI_ERR_IRB_TIMEOUT_A | \ + PI_ERR_IRB_ERR_A | \ + PI_ERR_PKT_LEN_ERR_A | \ PI_ERR_SYSSTATE_TAG_A | \ PI_ERR_BAD_SPOOL_A | \ PI_ERR_SYSCMD_ADDR_A | \ @@ -283,17 +285,17 @@ PI_ERR_SYSAD_DATA_A | \ PI_ERR_SYSSTATE_A) -#define PI_MISC_ERR_CPU_A (PI_ERR_IRB_TIMEOUT_A | \ - PI_ERR_IRB_ERR_A | \ - PI_ERR_PKT_LEN_ERR_A | \ - PI_ERR_UE_CACHED_A | \ +#define PI_MISC_ERR_CPU_A (PI_ERR_UE_CACHED_A | \ + PI_ERR_SYSAD_BAD_DATA_A| \ PI_ERR_UNCAC_UNCORR_A | \ PI_ERR_WRB_WERR_A | \ PI_ERR_WRB_TERR_A | \ PI_ERR_SPUR_MSG_A | \ PI_ERR_SPOOL_CMP_A) -#define PI_FATAL_ERR_CPU_B (PI_ERR_SYSAD_BAD_DATA_B | \ +#define PI_FATAL_ERR_CPU_B (PI_ERR_IRB_TIMEOUT_B | \ + PI_ERR_IRB_ERR_B | \ + PI_ERR_PKT_LEN_ERR_B | \ PI_ERR_SYSSTATE_TAG_B | \ PI_ERR_BAD_SPOOL_B | \ PI_ERR_SYSCMD_ADDR_B | \ @@ -302,11 +304,9 @@ PI_ERR_SYSAD_DATA_B | \ PI_ERR_SYSSTATE_B) -#define PI_MISC_ERR_CPU_B (PI_ERR_IRB_TIMEOUT_B | \ - PI_ERR_IRB_ERR_B | \ - PI_ERR_PKT_LEN_ERR_B | \ - PI_ERR_UE_CACHED_B | \ - PI_ERR_UNCAC_UNCORR_B | \ +#define PI_MISC_ERR_CPU_B (PI_ERR_UE_CACHED_B | \ + PI_ERR_SYSAD_BAD_DATA_B| \ + PI_ERR_UNCAC_UNCORR_B | \ PI_ERR_WRB_WERR_B | \ PI_ERR_WRB_TERR_B | \ PI_ERR_SPUR_MSG_B | \ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/hubxb_next.h linux/include/asm-ia64/sn/sn1/hubxb_next.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/hubxb_next.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/hubxb_next.h Thu Apr 5 12:51:47 2001 @@ -28,5 +28,6 @@ /* XB_PARMS fields */ #define XBP_RESET_DEFAULTS 0x0008000080000021LL +#define XBP_ACTIVE_DEFAULTS 0x00080000fffff021LL #endif /* _ASM_SN_SN1_HUBXB_NEXT_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/ip27config.h linux/include/asm-ia64/sn/sn1/ip27config.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/ip27config.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/ip27config.h Thu Apr 5 12:51:47 2001 @@ -188,6 +188,10 @@ #define IP27C_R10000_SCCD_MASK (7 << IP27C_R10000_SCCD_SHFT) #define IP27C_R10000_SCCD(_B) ((_B) << IP27C_R10000_SCCD_SHFT) +#define IP27C_R10000_DDR_SHFT 23 +#define IP27C_R10000_DDR_MASK (1 << IP27C_R10000_DDR_SHFT) +#define IP27C_R10000_DDR(_B) ((_B) << IP27C_R10000_DDR_SHFT) + #define IP27C_R10000_SCCT_SHFT 25 #define IP27C_R10000_SCCT_MASK (0xf << IP27C_R10000_SCCT_SHFT) #define IP27C_R10000_SCCT(_B) ((_B) << IP27C_R10000_SCCT_SHFT) @@ -375,6 +379,7 @@ IP27C_R10000_SCCE(0) + \ IP27C_R10000_ME(1) + \ IP27C_R10000_SCS(4) + \ + IP27C_R10000_DDR(1) + \ IP27C_R10000_SCCD(3) + \ IP27C_R10000_SCCT(0xa) + \ IP27C_R10000_ODSC(0) + \ @@ -503,12 +508,7 @@ * for building hex images (as required by start.s) */ #ifdef IP27_CONFIG_SN00_4MB_100_200_133 -#ifdef IRIX -/* Set PrcReqMax to 0 to reduce memory problems */ -#define BRINGUP_PRM_VAL 0 -#else #define BRINGUP_PRM_VAL 3 -#endif #define CONFIG_CPU_MODE \ (IP27C_R10000_KSEG0CA(5) + \ IP27C_R10000_DEVNUM(0) + \ @@ -593,6 +593,7 @@ IP27C_R10000_ME(1) + \ IP27C_R10000_SCS(4) + \ IP27C_R10000_SCCD(3) + \ + IP27C_R10000_DDR(1) + \ IP27C_R10000_SCCT(0xa) + \ IP27C_R10000_ODSC(0) + \ IP27C_R10000_ODSYS(1) + \ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/leds.h linux/include/asm-ia64/sn/sn1/leds.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/leds.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/leds.h Thu Apr 5 12:51:47 2001 @@ -25,7 +25,7 @@ long *ledp; int eid; - eid = hard_processor_sapicid() & 3; + eid = hard_smp_processor_id() & 3; ledp = (long*) (LED0 + (eid<<3)); *ledp = val; } diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/router.h linux/include/asm-ia64/sn/sn1/router.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/router.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/router.h Thu Apr 5 12:51:47 2001 @@ -513,7 +513,7 @@ #ifdef DEBUG int64_t ri_deltatime; /* Time it took to sample */ #endif - lock_t ri_lock; /* Lock for access to router info */ + spinlock_t ri_lock; /* Lock for access to router info */ net_vec_t *ri_vecarray; /* Pointer to array of vectors */ struct lboard_s *ri_brd; /* Pointer to board structure */ char * ri_name; /* This board's hwg path */ @@ -566,6 +566,7 @@ #define NORMAL_ROUTER_NAME "normal_router" #define NULL_ROUTER_NAME "null_router" #define META_ROUTER_NAME "meta_router" +#define REPEATER_ROUTER_NAME "repeater_router" #define UNKNOWN_ROUTER_NAME "unknown_router" /* The following definitions are needed by the router traversing @@ -630,7 +631,7 @@ */ #define RRM_RESETOK(_L) (UINT64_CAST 1 << ((_L) - 1)) -#define RRM_RESETOK_ALL (UINT64_CAST 0x3f) +#define RRM_RESETOK_ALL ALL_PORTS /* * RR_META_TABLE(_x) and RR_LOCAL_TABLE(_x) mask and shift definitions diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/slotnum.h linux/include/asm-ia64/sn/sn1/slotnum.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/slotnum.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/slotnum.h Thu Apr 5 12:51:47 2001 @@ -14,8 +14,7 @@ #define SLOTNUM_MAXLENGTH 16 /* - * This file attempts to define a slot number space across all slots - * a IP27 module. Here, we deal with the top level slots. + * This file attempts to define a slot number space across all slots. * * Node slots * Router slots @@ -24,16 +23,20 @@ * Other slots are children of their parent crosstalk slot: * PCI slots * VME slots + * + * The PCI class has been added since the XBridge ASIC on SN-MIPS + * has built-in PCI bridges (2). On IBricks, widget E & F serve + * PCI busses, and on PBricks all widgets serve as PCI busses + * with the use of the super-bridge mode of the XBridge ASIC. */ -// #include <slotnum.h> -// #ifdef NOTDEF /* moved to sys/slotnum.h */ #define SLOTNUM_NODE_CLASS 0x00 /* Node */ #define SLOTNUM_ROUTER_CLASS 0x10 /* Router */ #define SLOTNUM_XTALK_CLASS 0x20 /* Xtalk */ #define SLOTNUM_MIDPLANE_CLASS 0x30 /* Midplane */ #define SLOTNUM_XBOW_CLASS 0x40 /* Xbow */ #define SLOTNUM_KNODE_CLASS 0x50 /* Kego node */ +#define SLOTNUM_PCI_CLASS 0x60 /* PCI widgets on XBridge */ #define SLOTNUM_INVALID_CLASS 0xf0 /* Invalid */ #define SLOTNUM_CLASS_MASK 0xf0 @@ -41,7 +44,6 @@ #define SLOTNUM_GETCLASS(_sn) ((_sn) & SLOTNUM_CLASS_MASK) #define SLOTNUM_GETSLOT(_sn) ((_sn) & SLOTNUM_SLOT_MASK) -// #endif /* NOTDEF */ /* This determines module to pnode mapping. */ /* NODESLOTS_PER_MODULE has changed from 4 to 6 diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/uart16550.h linux/include/asm-ia64/sn/sn1/uart16550.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/uart16550.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/uart16550.h Thu Apr 5 12:51:47 2001 @@ -1,3 +1,16 @@ +/* $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 + */ + +#ifndef _ASM_SN_SN1_UART16550_H +#define _ASM_SN_SN1_UART16550_H + /* * Definitions for 16550 chip @@ -212,3 +225,4 @@ #define INC_RING_POINTER(x) \ ( ((x & 0xffe0) < 4064) ? (x += 32) : 0 ) +#endif /* _ASM_SN_SN1_UART16550_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn1/war.h linux/include/asm-ia64/sn/sn1/war.h --- v2.4.3/linux/include/asm-ia64/sn/sn1/war.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/war.h Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* $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 - */ -#ifndef _ASM_SN_SN1_WAR_H -#define _ASM_SN_SN1_WAR_H - -/**************************************************************************** - * Support macros and defitions for hardware workarounds in * - * early chip versions. * - ****************************************************************************/ - -/* - * This is the bitmap of runtime-switched workarounds. - */ -typedef short warbits_t; - -extern int warbits_override; - -#endif /* _ASM_SN_SN1_WAR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_cpuid.h linux/include/asm-ia64/sn/sn_cpuid.h --- v2.4.3/linux/include/asm-ia64/sn/sn_cpuid.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/sn_cpuid.h Thu Apr 5 12:51:47 2001 @@ -13,6 +13,7 @@ #define _ASM_IA64_SN_SN_CPUID_H #include <linux/config.h> +#include <asm/processor.h> #include <asm/sn/mmzone_sn1.h> /* @@ -26,18 +27,35 @@ /* - * The following assumes the following mappings for LID register values: + * Definitions of terms (these definitions are for IA64 ONLY. Other architectures + * use cpuid/cpunum quite defferently): + * + * CPUID - a number in range of 0..NR_CPUS-1 that uniquely identifies + * the cpu. The value cpuid has no significance on IA64 other than + * the boot cpu is 0. + * smp_processor_id() returns the cpuid of the current cpu. + * + * CPUNUM - On IA64, a cpunum and cpuid are the same. This is NOT true + * on other architectures like IA32. + * + * CPU_PHYSICAL_ID (also known as HARD_PROCESSOR_ID) + * This is the same as 31:24 of the processor LID register + * hard_smp_processor_id()- cpu_physical_id of current processor + * cpu_physical_id(cpuid) - convert a <cpuid> to a <physical_cpuid> + * cpu_logical_id(phy_id) - convert a <physical_cpuid> to a <cpuid> + * * not real efficient - dont use in perf critical code * - * LID + * LID - processor defined register (see PRM V2). * 31:24 - id Contains the NASID * 23:16 - eid Contains 0-3 to identify the cpu on the node * bit 17 - synergy number - * bit 16 - FSB number + * bit 16 - FSB slot number + * * - * SAPICID - * This is the same as 31:24 of LID * - * The macros convert between cpuid & slice/fsb/synergy/nasid/cnodeid. + * The following assumes the following mappings for LID register values: + * + * The macros convert between cpu physical ids & slice/fsb/synergy/nasid/cnodeid. * These terms are described below: * * @@ -46,7 +64,7 @@ * ----- ----- ----- ----- * | | | | * | | | | - * 0 | | 1 0 | | 1 FSB + * 0 | | 1 0 | | 1 FSB SLOT * ------- ------- * | | * | | @@ -68,25 +86,27 @@ * */ +#ifndef CONFIG_SMP +#define cpu_logical_id(cpu) 0 +#define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) +#endif - -#define sapicid_to_nasid(sid) ((sid) >> 8) -#define sapicid_to_synergy(sid) (((sid) >> 1) & 1) -#define sapicid_to_fsb(sid) ((sid) & 1) -#define sapicid_to_slice(sid) ((sid) & 3) +#define cpu_physical_id_to_nasid(cpi) ((cpi) >> 8) +#define cpu_physical_id_to_synergy(cpi) (((cpi) >> 1) & 1) +#define cpu_physical_id_to_fsb_slot(cpi) ((cpi) & 1) +#define cpu_physical_id_to_slice(cpi) ((cpi) & 3) /* * NOTE: id & eid refer to Intels definitions of the LID register * (id = NASID, eid = slice) * NOTE: on non-MP systems, only cpuid 0 exists */ -#define id_eid_to_sapicid(id,eid) (((id)<<8) | (eid)) -#define id_eid_to_cpuid(id,eid) ((NASID_TO_CNODEID(id)<<2) | (eid)) +#define id_eid_to_cpu_physical_id(id,eid) (((id)<<8) | (eid)) +#define id_eid_to_cpuid(id,eid) (cpu_logical_id(id_eid_to_cpu_physical_id((id),(eid)))) /* - * The following table/struct is for translating between sapicid and cpuids. - * It is also used for managing PTC coherency domains. + * The following table/struct is used for managing PTC coherency domains. */ typedef struct { u8 domain; @@ -99,28 +119,13 @@ /* - * cpuid_to_spaicid - Convert a cpuid to a SAPIC id of the cpu. - * The SAPIC id is the same as bits 31:16 of the LID register. - */ -static __inline__ int -cpuid_to_spaicid(int cpuid) -{ -#ifdef CONFIG_SMP - return cpu_physical_id(cpuid); -#else - return ((ia64_get_lid() >> 16) & 0xffff); -#endif -} - - -/* * cpuid_to_fsb_slot - convert a cpuid to the fsb slot number that it is in. * (there are 2 cpus per FSB. This function returns 0 or 1) */ static __inline__ int cpuid_to_fsb_slot(int cpuid) { - return sapicid_to_fsb(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_fsb_slot(cpu_physical_id(cpuid)); } @@ -132,7 +137,7 @@ static __inline__ int cpuid_to_synergy(int cpuid) { - return sapicid_to_synergy(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_synergy(cpu_physical_id(cpuid)); } @@ -143,7 +148,7 @@ static __inline__ int cpuid_to_slice(int cpuid) { - return sapicid_to_slice(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_slice(cpu_physical_id(cpuid)); } @@ -153,7 +158,7 @@ static __inline__ int cpuid_to_nasid(int cpuid) { - return sapicid_to_nasid(cpuid_to_spaicid(cpuid)); + return cpu_physical_id_to_nasid(cpu_physical_id(cpuid)); } @@ -166,23 +171,42 @@ return nasid_map[cpuid_to_nasid(cpuid)]; } +/* + * cnodeid_to_nasid - convert a cnodeid to a NASID + */ static __inline__ int cnodeid_to_nasid(int cnodeid) { - int i; - for (i = 0; i < MAXNASIDS; i++) { - if (nasid_map[i] == cnodeid) { - return(i); - } - } - return(-1); + if (nasid_map[cnodeid_map[cnodeid]] != cnodeid) + panic("cnodeid_to_nasid, cnode = %d", cnodeid); + return cnodeid_map[cnodeid]; } +/* + * nasid_to_cnodeid - convert a NASID to a cnodeid + */ +static __inline__ int +nasid_to_cnodeid(int nasid) +{ + if (cnodeid_map[nasid_map[nasid]] != nasid) + panic("nasid_to_cnodeid"); + return nasid_map[nasid]; +} + + +/* + * cnode_slice_to_cpuid - convert a codeid & slice to a cpuid + */ static __inline__ int cnode_slice_to_cpuid(int cnodeid, int slice) { return(id_eid_to_cpuid(cnodeid_to_nasid(cnodeid),slice)); } +/* + * cpuid_to_subnode - convert a cpuid to the subnode it resides on. + * slice 0 & 1 are on subnode 0 + * slice 2 & 3 are on subnode 1. + */ static __inline__ int cpuid_to_subnode(int cpuid) { int ret = cpuid_to_slice(cpuid); @@ -190,9 +214,27 @@ else return 1; } +/* + * cpuid_to_localslice - convert a cpuid to a local slice + * slice 0 & 2 are local slice 0 + * slice 1 & 3 are local slice 1 + */ static __inline__ int cpuid_to_localslice(int cpuid) { return(cpuid_to_slice(cpuid) & 1); +} + +static __inline__ int +cnodeid_to_cpuid(int cnode) { + int cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (cpuid_to_cnodeid(cpu) == cnode) { + break; + } + } + if (cpu == smp_num_cpus) cpu = -1; + return cpu; } diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_fru.h linux/include/asm-ia64/sn/sn_fru.h --- v2.4.3/linux/include/asm-ia64/sn/sn_fru.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn_fru.h Thu Apr 5 12:51:47 2001 @@ -1,16 +1,14 @@ -/************************************************************************** - * * - * Copyright (C) 1992-1997, Silicon Graphics, Inc. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - **************************************************************************/ -#ifndef __SYS_SN_SN0_FRU_H__ -#define __SYS_SN_SN0_FRU_H__ +/* $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, 1999-2000 Silicon Graphics, Inc. + * Copyright (C) 2000 by Patrick Gefre + */ +#ifndef _ASM_SN_SN_FRU_H +#define _ASM_SN_SN_FRU_H #define MAX_DIMMS 8 /* max # of dimm banks */ #define MAX_PCIDEV 8 /* max # of pci devices on a pci bus */ @@ -44,6 +42,5 @@ } kf_pci_bus_t; - -#endif /* #ifdef __SYS_SN_SN0_FRU_H__ */ +#endif /* _ASM_SN_SN_FRU_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_private.h linux/include/asm-ia64/sn/sn_private.h --- v2.4.3/linux/include/asm-ia64/sn/sn_private.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/sn_private.h Thu Apr 5 12:51:47 2001 @@ -10,7 +10,6 @@ #ifndef _ASM_SN_PRIVATE_H #define _ASM_SN_PRIVATE_H -#include <linux/config.h> #include <asm/sn/nodepda.h> #include <asm/sn/xtalk/xwidget.h> #include <asm/sn/xtalk/xtalk_private.h> @@ -20,12 +19,12 @@ extern hubreg_t get_region(cnodeid_t); extern hubreg_t nasid_to_region(nasid_t); /* promif.c */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern cpuid_t cpu_node_probe(cpumask_t *cpumask, int *numnodes); #endif extern void he_arcs_set_vectors(void); extern void mem_init(void); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern int cpu_enabled(cpuid_t); #endif extern void cpu_unenable(cpuid_t); @@ -35,7 +34,7 @@ extern int check_nasid_equiv(nasid_t, nasid_t); extern nasid_t get_console_nasid(void); extern char get_console_pcislot(void); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); #endif @@ -112,19 +111,19 @@ /* init.c */ extern cnodeid_t get_compact_nodeid(void); /* get compact node id */ -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node); extern void init_platform_pda(pda_t *ppda, cpuid_t cpu); #endif extern void per_cpu_init(void); extern void per_hub_init(cnodeid_t); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER extern cpumask_t boot_cpumask; #endif extern int is_fine_dirmode(void); extern void update_node_information(cnodeid_t); -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER /* clksupport.c */ extern void early_counter_intr(eframe_t *); #endif @@ -251,7 +250,7 @@ /* IP27 cpu-specific information stored under INFO_LBL_CPU_INFO */ /* TBD: IP27-dependent stuff currently in pda.h should be here */ typedef struct cpuinfo_s { -#ifndef CONFIG_IA64_SGI_IO +#ifdef LATER pda_t *ci_cpupda; /* pointer to CPU's private data area */ #endif cpuid_t ci_cpuid; /* CPU ID */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sn_sal.h linux/include/asm-ia64/sn/sn_sal.h --- v2.4.3/linux/include/asm-ia64/sn/sn_sal.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ia64/sn/sn_sal.h Thu Apr 5 12:51:47 2001 @@ -0,0 +1,25 @@ +#ifndef _ASM_IA64_SN_SAL_H +#define _ASM_IA64_SN_SAL_H + +/* + * System Abstraction Layer definitions for IA64 + * + * + * Copyright (C) 2000, Silicon Graphics. + * Copyright (C) 2000. Jack Steiner (steiner@sgi.com) + */ + + +#include <asm/sal.h> + + +// SGI Specific Calls +#define SN_SAL_POD_MODE 0x02000001 +#define SN_SAL_SYSTEM_RESET 0x02000002 +#define SN_SAL_PROBE 0x02000003 + + +u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr); + + +#endif /* _ASM_IA64_SN_SN1_SAL_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/sv.h linux/include/asm-ia64/sn/sv.h --- v2.4.3/linux/include/asm-ia64/sn/sv.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ia64/sn/sv.h Thu Apr 5 12:51:47 2001 @@ -0,0 +1,153 @@ +/* + * 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 <lord@sgi.com> + * + * Paul Cassella <pwc@sgi.com> + */ + +#ifndef SV_H +#define SV_H + +#include <linux/spinlock.h> +#include <asm/semaphore.h> + +#ifndef ASSERT + +#define ASSERT(x) do { \ + if(!(x)) { \ + printk(KERN_ERR "%s\n", "Assertion failed: " # x); \ + BUG(); \ + } \ + } while(0) +#define _SV_ASSERT +#endif + +typedef void sv_mon_lock_t; +typedef void (*sv_mon_unlock_func_t)(sv_mon_lock_t *lock); + +/* sv_flags values: */ + +#define SV_ORDER_FIFO 0x001 +#define SV_ORDER_FILO 0x002 +#define SV_ORDER_LIFO SV_ORDER_FILO + +/* If at some point one order becomes preferable to others, we can + switch to it if the caller of sv_init doesn't specify. */ +#define SV_ORDER_DEFAULT SV_ORDER_FIFO + +#define SV_ORDER_MASK 0x00f + + +#define SV_MON_SEMA 0x010 +#define SV_MON_SPIN 0x020 + +#define SV_MON_MASK 0x0f0 + + +/* + If the monitor lock can be aquired from interrupts. Note that this + is a superset of the cases in which the sv can be touched from + interrupts. + + This is currently only valid when the monitor lock is a spinlock. + + If this is used, sv_wait, sv_signal, and sv_broadcast must all be + called with interrupts disabled, which has to happen anyway to have + acquired the monitor spinlock. + */ +#define SV_INTS 0x100 + +/* ditto for bottom halves */ +#define SV_BHS 0x200 + + + +/* sv_wait_flag values: */ +#define SV_WAIT_SIG 0x001 /* Allow sv_wait to be interrupted by a signal */ + +typedef struct sv_s { + wait_queue_head_t sv_waiters; + sv_mon_lock_t *sv_mon_lock; /* Lock held for exclusive access to monitor. */ + sv_mon_unlock_func_t sv_mon_unlock_func; + spinlock_t sv_lock; /* Spinlock protecting the sv itself. */ + int sv_flags; +} sv_t; + +#define DECLARE_SYNC_VARIABLE(sv, l, f) sv_t sv = sv_init(&sv, l, f) + +/* + * @sv the sync variable to initialize + * @monitor_lock the lock enforcing exclusive running in the monitor + * @flags one of + * SV_MON_SEMA monitor_lock is a semaphore + * SV_MON_SPIN monitor_lock is a spinlock + * and a bitwise or of some subset of + * SV_INTS - the monitor lock can be acquired from interrupts (and + * hence, whenever we hold it, interrupts are disabled or + * we're in an interrupt.) This is only valid when + * SV_MON_SPIN is set. + */ +void sv_init(sv_t *sv, sv_mon_lock_t *monitor_lock, int flags); + +/* + * Set SV_WAIT_SIG in sv_wait_flags to let the sv_wait be interrupted by signals. + * + * timeout is how long to wait before giving up, or 0 to wait + * indefinately. It is given in jiffies, and is relative. + * + * 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 + */ +extern signed long sv_wait(sv_t *sv, int sv_wait_flags, + unsigned long timeout /* relative jiffies */); + +static inline int sv_wait_compat(sv_t *sv, sv_mon_lock_t *lock, int sv_wait_flags, + unsigned long timeout, int sv_mon_type) +{ + ASSERT(sv_mon_type == (sv->sv_flags & SV_MON_MASK)); + if(sv->sv_mon_lock) + ASSERT(lock == sv->sv_mon_lock); + else + sv->sv_mon_lock = lock; + + return sv_wait(sv, sv_wait_flags, timeout); +} + + +/* These work like Irix's sv_wait() and sv_wait_sig(), except the + caller must call the one correpsonding to the type of the monitor + lock. */ +#define sv_spin_wait(sv, lock) \ + sv_wait_compat(sv, lock, 0, 0, SV_MON_SPIN) +#define sv_spin_wait_sig(sv, lock) \ + sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SPIN) + +#define sv_sema_wait(sv, lock) \ + sv_wait_compat(sv, lock, 0, 0, SV_MON_SEMA) +#define sv_sema_wait_sig(sv, lock) \ + sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SEMA) + +/* These work as in Irix. */ +void sv_signal(sv_t *sv); +void sv_broadcast(sv_t *sv); + +/* This works as in Irix. */ +void sv_destroy(sv_t *sv); + +#ifdef _SV_ASSERT +#undef ASSERT +#undef _SV_ASSERT +#endif + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/synergy.h linux/include/asm-ia64/sn/synergy.h --- v2.4.3/linux/include/asm-ia64/sn/synergy.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/synergy.h Thu Apr 12 12:16:36 2001 @@ -1,7 +1,10 @@ #ifndef ASM_IA64_SN_SYNERGY_H #define ASM_IA64_SN_SYNERGY_H +#include <linux/config.h> + #include "asm/io.h" +#include "asm/sn/nodepda.h" #include "asm/sn/intr_public.h" @@ -41,47 +44,52 @@ #define WRITE_LOCAL_SYNERGY_REG(addr, value) __synergy_out(addr, value) #define HUBREG_CAST (volatile hubreg_t *) -#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) -#define SYN_UNCACHED_SPACE 0xc000000000000000 -#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) -#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) -#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) +#define HUB_L(_a) *(_a) +#define HUB_S(_a, _d) *(_a) = (_d) + +#define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ +#define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ +#define HS_SYNERGY_STRIDE (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0) #define REMOTE_HSPEC(_n, _x) (HUBREG_CAST (RREG_BASE(_n) + (_x))) -#define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ -#define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ -#define HS_SYNERGY_STRIDE (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0) +#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) +#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) +#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) +#ifndef HSPEC_BASE +#define HSPEC_BASE (SYN_UNCACHED_SPACE | HSPEC_BASE_SYN) +#endif +#define SYN_UNCACHED_SPACE 0xc000000000000000 +#define HSPEC_BASE_SYN 0x00000b0000000000 +#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) +#define NODE_SIZE_BITS 33 -#define HUB_L(_a) *(_a) -#define HUB_S(_a, _d) *(_a) = (_d) +#define RSYN_REG_OFFSET(fsb, reg) (((fsb) ? HSPEC_SYNERGY1_0 : HSPEC_SYNERGY0_0) | (reg)) #define REMOTE_SYNERGY_LOAD(nasid, fsb, reg) __remote_synergy_in(nasid, fsb, reg) #define REMOTE_SYNERGY_STORE(nasid, fsb, reg, val) __remote_synergy_out(nasid, fsb, reg, val) -extern inline void -__remote_synergy_out(int nasid, int fsb, unsigned long reg, unsigned long val) { - unsigned long addr = ((RREG_BASE(nasid)) + - ((HSPEC_SYNERGY0_0 | (fsb)*HS_SYNERGY_STRIDE) | ((reg) << 2))); - - HUB_S((unsigned long *)(addr), (val) >> 48); - HUB_S((unsigned long *)(addr+0x08), (val) >> 32); - HUB_S((unsigned long *)(addr+0x10), (val) >> 16); - HUB_S((unsigned long *)(addr+0x18), (val) ); - __ia64_mf_a(); +extern inline uint64_t +__remote_synergy_in(int nasid, int fsb, uint64_t reg) { + volatile uint64_t *addr; + + addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, reg)); + return (*addr); } -extern inline unsigned long -__remote_synergy_in(int nasid, int fsb, unsigned long reg) { - volatile unsigned long *addr = (unsigned long *) ((RREG_BASE(nasid)) + - ((HSPEC_SYNERGY0_0 | (fsb)*HS_SYNERGY_STRIDE) | (reg))); - unsigned long ret; +extern inline void +__remote_synergy_out(int nasid, int fsb, uint64_t reg, uint64_t value) { + volatile uint64_t *addr; - ret = *addr; - __ia64_mf_a(); - return ret; + addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, (reg<<2))); + *(addr+0) = value >> 48; + *(addr+1) = value >> 32; + *(addr+2) = value >> 16; + *(addr+3) = value; + __ia64_mf_a(); } +/* XX this doesn't make a lot of sense. Which fsb? */ extern inline void __synergy_out(unsigned long addr, unsigned long value) { @@ -94,6 +102,7 @@ #define READ_LOCAL_SYNERGY_REG(addr) __synergy_in(addr) +/* XX this doesn't make a lot of sense. Which fsb? */ extern inline unsigned long __synergy_in(unsigned long addr) { @@ -120,7 +129,39 @@ spinlock_t action_list_lock; struct sn1_intr_action *action_list; }; - + +#if defined(CONFIG_IA64_SGI_SYNERGY_PERF) + +/* multiplex the counters every 10 timer interrupts */ +#define SYNERGY_PERF_FREQ_DEFAULT 10 + +/* synergy perf control registers */ +#define PERF_CNTL0_A 0xab0UL /* control A on FSB0 */ +#define PERF_CNTL0_B 0xab8UL /* control B on FSB0 */ +#define PERF_CNTL1_A 0xac0UL /* control A on FSB1 */ +#define PERF_CNTL1_B 0xac8UL /* control B on FSB1 */ + +/* synergy perf counters */ +#define PERF_CNTR0_A 0xad0UL /* counter A on FSB0 */ +#define PERF_CNTR0_B 0xad8UL /* counter B on FSB0 */ +#define PERF_CNTR1_A 0xaf0UL /* counter A on FSB1 */ +#define PERF_CNTR1_B 0xaf8UL /* counter B on FSB1 */ + +/* Synergy perf data. Each nodepda keeps a list of these */ +struct synergy_perf_s { + uint64_t intervals; /* count of active intervals for this event */ + uint64_t modesel; /* mode and sel bits, both A and B registers */ + struct synergy_perf_s *next; /* next in circular linked list */ + uint64_t counts[2]; /* [0] is synergy-A counter, [1] synergy-B counter */ +}; + +typedef struct synergy_perf_s synergy_perf_t; + +extern void synergy_perf_init(void); +extern void synergy_perf_update(int); + +#endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ + /* Temporary defintions for testing: */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/types.h linux/include/asm-ia64/sn/types.h --- v2.4.3/linux/include/asm-ia64/sn/types.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/types.h Thu Apr 5 12:51:47 2001 @@ -9,7 +9,6 @@ #ifndef _ASM_SN_TYPES_H #define _ASM_SN_TYPES_H -#include <linux/config.h> #include <linux/types.h> typedef unsigned long cpuid_t; @@ -22,15 +21,12 @@ typedef signed short cmoduleid_t; /* kernel compact module id type */ typedef unsigned char clusterid_t; /* Clusterid of the cell */ -#if defined(CONFIG_IA64_SGI_IO) #define __psunsigned_t uint64_t #define lock_t uint64_t -#define sv_t uint64_t typedef unsigned long iopaddr_t; typedef unsigned char uchar_t; typedef unsigned long paddr_t; typedef unsigned long pfn_t; -#endif /* CONFIG_IA64_SGI_IO */ #endif /* _ASM_SN_TYPES_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/war.h linux/include/asm-ia64/sn/war.h --- v2.4.3/linux/include/asm-ia64/sn/war.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/war.h Wed Dec 31 16:00:00 1969 @@ -1,18 +0,0 @@ -/* $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 - */ -#ifndef _ASM_SN_WAR_H -#define _ASM_SN_WAR_H - -#include <linux/config.h> -#if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#include <asm/sn/sn1/war.h> -#endif - -#endif /* _ASM_SN_WAR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk.h linux/include/asm-ia64/sn/xtalk/xtalk.h --- v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/xtalk/xtalk.h Thu Apr 5 12:51:47 2001 @@ -278,6 +278,7 @@ /* INTERRUPT MANAGEMENT */ xtalk_intr_alloc_f *intr_alloc; + xtalk_intr_alloc_f *intr_alloc_nothd; xtalk_intr_free_f *intr_free; xtalk_intr_connect_f *intr_connect; xtalk_intr_disconnect_f *intr_disconnect; @@ -308,6 +309,7 @@ extern xtalk_dmaaddr_drain_f xtalk_dmaaddr_drain; extern xtalk_dmalist_drain_f xtalk_dmalist_drain; extern xtalk_intr_alloc_f xtalk_intr_alloc; +extern xtalk_intr_alloc_f xtalk_intr_alloc_nothd; extern xtalk_intr_free_f xtalk_intr_free; extern xtalk_intr_connect_f xtalk_intr_connect; extern xtalk_intr_disconnect_f xtalk_intr_disconnect; @@ -342,10 +344,6 @@ extern iopaddr_t xtalk_intr_addr_get(xtalk_intr_t xtalk_intr); extern devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr); extern void *xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr); - -extern int xtalk_intr_flags_get(xtalk_intr_t xtalk_intr); -/* XTALK_INTR flags */ -#define XTALK_INTR_NOTHREAD 1 /* interrupt handler wants to be called at interrupt level */ /* Generic crosstalk pio interfaces */ extern devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap); diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk_private.h linux/include/asm-ia64/sn/xtalk/xtalk_private.h --- v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalk_private.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/xtalk/xtalk_private.h Thu Apr 5 12:51:47 2001 @@ -10,11 +10,7 @@ #ifndef _ASM_SN_XTALK_XTALK_PRIVATE_H #define _ASM_SN_XTALK_XTALK_PRIVATE_H -#ifdef IRIX -#include <sys/ioerror.h> /* for error function and arg types */ -#else #include <asm/sn/ioerror.h> /* for error function and arg types */ -#endif /* * xtalk_private.h -- private definitions for xtalk @@ -44,7 +40,6 @@ * All Crosstalk providers set up interrupts using this information. */ struct xtalk_intr_s { - int xi_flags; /* XTALK_INTR flags */ devfs_handle_t xi_dev; /* requestor of this intr */ xwidgetnum_t xi_target; /* master's widget number */ xtalk_intr_vector_t xi_vector; /* 8-bit interrupt vector */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h --- v2.4.3/linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h Thu Jan 4 15:25:55 2001 +++ linux/include/asm-ia64/sn/xtalk/xtalkaddrs.h Thu Apr 5 12:51:47 2001 @@ -10,6 +10,8 @@ #ifndef _ASM_SN_XTALK_XTALKADDRS_H #define _ASM_SN_XTALK_XTALKADDRS_H +#include <linux/config.h> + /* * CrossTalk to SN0 Hub addressing support * @@ -58,8 +60,6 @@ * This looks very much like a REMOTE_HUB access, except the nodeID * is in a different place, and the highest xtalk bit is set. */ - -#include <linux/config.h> /* Hub-specific xtalk definitions */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/softirq.h linux/include/asm-ia64/softirq.h --- v2.4.3/linux/include/asm-ia64/softirq.h Fri Mar 10 15:24:02 2000 +++ linux/include/asm-ia64/softirq.h Thu Apr 5 12:51:47 2001 @@ -2,17 +2,14 @@ #define _ASM_IA64_SOFTIRQ_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/hardirq.h> -#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0) -#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0) +#define local_bh_disable() do { local_bh_count()++; barrier(); } while (0) +#define local_bh_enable() do { barrier(); local_bh_count()--; } while (0) -#define local_bh_disable() cpu_bh_disable(smp_processor_id()) -#define local_bh_enable() cpu_bh_enable(smp_processor_id()) - -#define in_softirq() (local_bh_count(smp_processor_id()) != 0) +#define in_softirq() (local_bh_count() != 0) #endif /* _ASM_IA64_SOFTIRQ_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h --- v2.4.3/linux/include/asm-ia64/system.h Tue Mar 6 19:44:34 2001 +++ linux/include/asm-ia64/system.h Thu Apr 5 12:51:47 2001 @@ -7,8 +7,8 @@ * on information published in the Processor Abstraction Layer * and the System Abstraction Layer manual. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> */ @@ -16,16 +16,18 @@ #include <asm/page.h> -#define KERNEL_START (PAGE_OFFSET + 0x500000) +#define KERNEL_START (PAGE_OFFSET + 68*1024*1024) /* * The following #defines must match with vmlinux.lds.S: */ +#define IVT_ADDR (KERNEL_START) #define IVT_END_ADDR (KERNEL_START + 0x8000) -#define ZERO_PAGE_ADDR (IVT_END_ADDR + 0*PAGE_SIZE) -#define SWAPPER_PGD_ADDR (IVT_END_ADDR + 1*PAGE_SIZE) +#define ZERO_PAGE_ADDR PAGE_ALIGN(IVT_END_ADDR) +#define SWAPPER_PGD_ADDR (ZERO_PAGE_ADDR + 1*PAGE_SIZE) #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) +#define PERCPU_ADDR (0xa000000000000000 + 2*PAGE_SIZE) #if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) @@ -62,12 +64,10 @@ __u16 orig_x; /* cursor's x position */ __u16 orig_y; /* cursor's y position */ } console_info; - __u16 num_pci_vectors; /* number of ACPI derived PCI IRQ's*/ - __u64 pci_vectors; /* physical address of PCI data (pci_vector_struct)*/ __u64 fpswa; /* physical address of the fpswa interface */ __u64 initrd_start; __u64 initrd_size; -} ia64_boot_param; +} *ia64_boot_param; static inline void ia64_insn_group_barrier (void) @@ -181,50 +181,9 @@ #define __save_flags(flags) __asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory") #define __save_and_cli(flags) local_irq_save(flags) #define save_and_cli(flags) __save_and_cli(flags) - - -#ifdef CONFIG_IA64_SOFTSDV_HACKS -/* - * Yech. SoftSDV has a slight probem with psr.i and itc/itm. If - * PSR.i = 0 and ITC == ITM, you don't get the timer tick posted. So, - * I'll check if ITC is larger than ITM here and reset if neccessary. - * I may miss a tick to two. - * - * Don't include asm/delay.h; it causes include loops that are - * mind-numbingly hard to follow. - */ - -#define get_itc(x) __asm__ __volatile__("mov %0=ar.itc" : "=r"((x)) :: "memory") -#define get_itm(x) __asm__ __volatile__("mov %0=cr.itm" : "=r"((x)) :: "memory") -#define set_itm(x) __asm__ __volatile__("mov cr.itm=%0" :: "r"((x)) : "memory") - -#define __restore_flags(x) \ -do { \ - unsigned long itc, itm; \ - local_irq_restore(x); \ - get_itc(itc); \ - get_itm(itm); \ - if (itc > itm) \ - set_itm(itc + 10); \ -} while (0) - -#define __sti() \ -do { \ - unsigned long itc, itm; \ - local_irq_enable(); \ - get_itc(itc); \ - get_itm(itm); \ - if (itc > itm) \ - set_itm(itc + 10); \ -} while (0) - -#else /* !CONFIG_IA64_SOFTSDV_HACKS */ - #define __sti() local_irq_enable () #define __restore_flags(flags) local_irq_restore(flags) -#endif /* !CONFIG_IA64_SOFTSDV_HACKS */ - #ifdef CONFIG_SMP extern void __global_cli (void); extern void __global_sti (void); @@ -325,7 +284,7 @@ #define xchg(ptr,x) \ ((__typeof__(*(ptr))) __xchg ((unsigned long) (x), (ptr), sizeof(*(ptr)))) -/* +/* * Atomic compare and exchange. Compare OLD with MEM, if identical, * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. @@ -350,7 +309,7 @@ case 2: _o_ = (__u16) (long) (old); break; \ case 4: _o_ = (__u32) (long) (old); break; \ case 8: _o_ = (__u64) (long) (old); break; \ - default: \ + default: break; \ } \ __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ switch (size) { \ @@ -439,7 +398,7 @@ (last) = ia64_switch_to((next)); \ } while (0) -#ifdef CONFIG_SMP +#ifdef CONFIG_SMP /* * In the SMP case, we save the fph state when context-switching * away from a thread that modified fph. This way, when the thread diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/timex.h linux/include/asm-ia64/timex.h --- v2.4.3/linux/include/asm-ia64/timex.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/timex.h Thu Apr 5 12:51:47 2001 @@ -2,14 +2,15 @@ #define _ASM_IA64_TIMEX_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + */ +/* + * 2001/01/18 davidm Removed CLOCK_TICK_RATE. It makes no sense on IA-64. + * Also removed cacheflush_time as it's entirely unused. */ - -#define CLOCK_TICK_RATE 1193180 /* Underlying HZ XXX fix me! */ typedef unsigned long cycles_t; -extern cycles_t cacheflush_time; static inline cycles_t get_cycles (void) diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/uaccess.h linux/include/asm-ia64/uaccess.h --- v2.4.3/linux/include/asm-ia64/uaccess.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/uaccess.h Thu Apr 5 12:51:47 2001 @@ -25,14 +25,16 @@ * handler checks to see whether the faulting instruction has a fixup * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and * then resumes execution at the continuation point. - * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/errno.h> #include <linux/sched.h> +#include <asm/pgtable.h> + /* * For historical reasons, the following macros are grossly misnamed: */ @@ -49,16 +51,13 @@ #define segment_eq(a,b) ((a).seg == (b).seg) /* - * When accessing user memory, we need to make sure the entire area - * really is in user-level space. In order to do this efficiently, we - * make sure that the page at address TASK_SIZE is never valid (we do - * this by selecting VMALLOC_START as TASK_SIZE+PAGE_SIZE). This way, - * we can simply check whether the starting address is < TASK_SIZE - * and, if so, start accessing the memory. If the user specified bad - * length, we will fault on the NaT page and then return the - * appropriate error. + * When accessing user memory, we need to make sure the entire area really is in + * user-level space. In order to do this efficiently, we make sure that the page at + * address TASK_SIZE is never valid. We also need to make sure that the address doesn't + * point inside the virtually mapped linear page table. */ -#define __access_ok(addr,size,segment) (((unsigned long) (addr)) <= (segment).seg) +#define __access_ok(addr,size,segment) (((unsigned long) (addr)) <= (segment).seg \ + && ((segment).seg == KERNEL_DS.seg || rgn_offset((unsigned long) (addr)) < RGN_MAP_LIMIT)) #define access_ok(type,addr,size) __access_ok((addr),(size),get_fs()) static inline int @@ -85,28 +84,28 @@ */ #define __put_user(x,ptr) __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) - + extern void __get_user_unknown (void); -#define __get_user_nocheck(x,ptr,size) \ -({ \ - register long __gu_err __asm__ ("r8") = 0; \ - register long __gu_val __asm__ ("r9") = 0; \ - switch (size) { \ - case 1: __get_user_8(ptr); break; \ - case 2: __get_user_16(ptr); break; \ - case 4: __get_user_32(ptr); break; \ - case 8: __get_user_64(ptr); break; \ - default: __get_user_unknown(); break; \ - } \ - (x) = (__typeof__(*(ptr))) __gu_val; \ - __gu_err; \ +#define __get_user_nocheck(x,ptr,size) \ +({ \ + register long __gu_err asm ("r8") = 0; \ + register long __gu_val asm ("r9") = 0; \ + switch (size) { \ + case 1: __get_user_8(ptr); break; \ + case 2: __get_user_16(ptr); break; \ + case 4: __get_user_32(ptr); break; \ + case 8: __get_user_64(ptr); break; \ + default: __get_user_unknown(); break; \ + } \ + (x) = (__typeof__(*(ptr))) __gu_val; \ + __gu_err; \ }) #define __get_user_check(x,ptr,size,segment) \ ({ \ - register long __gu_err __asm__ ("r8") = -EFAULT; \ - register long __gu_val __asm__ ("r9") = 0; \ + register long __gu_err asm ("r8") = -EFAULT; \ + register long __gu_val asm ("r9") = 0; \ const __typeof__(*(ptr)) *__gu_addr = (ptr); \ if (__access_ok((long)__gu_addr,size,segment)) { \ __gu_err = 0; \ @@ -126,46 +125,60 @@ #define __m(x) (*(struct __large_struct *)(x)) /* We need to declare the __ex_table section before we can use it in .xdata. */ -__asm__ (".section \"__ex_table\", \"a\"\n\t.previous"); +asm (".section \"__ex_table\", \"a\"\n\t.previous"); + +#if __GNUC__ >= 3 +# define GAS_HAS_LOCAL_TAGS /* define if gas supports local tags a la [1:] */ +#endif + +#ifdef GAS_HAS_LOCAL_TAGS +# define _LL "[1:]" +#else +# define _LL "1:" +#endif #define __get_user_64(addr) \ - __asm__ ("\n1:\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld8 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_32(addr) \ - __asm__ ("\n1:\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld4 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_16(addr) \ - __asm__ ("\n1:\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld2 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); #define __get_user_8(addr) \ - __asm__ ("\n1:\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)|1\n" \ - : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); + asm ("\n"_LL"\tld1 %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)+4\n" \ + _LL \ + : "=r"(__gu_val), "=r"(__gu_err) : "m"(__m(addr)), "1"(__gu_err)); extern void __put_user_unknown (void); -#define __put_user_nocheck(x,ptr,size) \ -({ \ - register long __pu_err __asm__ ("r8") = 0; \ - switch (size) { \ - case 1: __put_user_8(x,ptr); break; \ - case 2: __put_user_16(x,ptr); break; \ - case 4: __put_user_32(x,ptr); break; \ - case 8: __put_user_64(x,ptr); break; \ - default: __put_user_unknown(); break; \ - } \ - __pu_err; \ +#define __put_user_nocheck(x,ptr,size) \ +({ \ + register long __pu_err asm ("r8") = 0; \ + switch (size) { \ + case 1: __put_user_8(x,ptr); break; \ + case 2: __put_user_16(x,ptr); break; \ + case 4: __put_user_32(x,ptr); break; \ + case 8: __put_user_64(x,ptr); break; \ + default: __put_user_unknown(); break; \ + } \ + __pu_err; \ }) #define __put_user_check(x,ptr,size,segment) \ ({ \ - register long __pu_err __asm__ ("r8") = -EFAULT; \ + register long __pu_err asm ("r8") = -EFAULT; \ __typeof__(*(ptr)) *__pu_addr = (ptr); \ if (__access_ok((long)__pu_addr,size,segment)) { \ __pu_err = 0; \ @@ -186,27 +199,31 @@ * any memory gcc knows about, so there are no aliasing issues */ #define __put_user_64(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst8 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_32(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst4 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_16(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst2 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) #define __put_user_8(x,addr) \ - __asm__ __volatile__ ( \ - "\n1:\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ - "2:\n\t.xdata4 \"__ex_table\", @gprel(1b), (2b-1b)\n" \ + asm volatile ( \ + "\n"_LL"\tst1 %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", @gprel(1b), @gprel(1f)\n" \ + _LL \ : "=r"(__pu_err) : "m"(__m(addr)), "rO"(x), "0"(__pu_err)) /* @@ -215,7 +232,7 @@ extern unsigned long __copy_user (void *to, const void *from, unsigned long count); #define __copy_to_user(to,from,n) __copy_user((to), (from), (n)) -#define __copy_from_user(to,from,n) __copy_user((to), (from), (n)) +#define __copy_from_user(to,from,n) __copy_user((to), (from), (n)) #define copy_to_user(to,from,n) __copy_tofrom_user((to), (from), (n), 1) #define copy_from_user(to,from,n) __copy_tofrom_user((to), (from), (n), 0) @@ -293,10 +310,14 @@ struct exception_table_entry { int addr; /* gp-relative address of insn this fixup is for */ - int skip; /* number of bytes to skip to get to the continuation point. - Bit 0 tells us if r9 should be cleared to 0*/ + int cont; /* gp-relative continuation address; if bit 2 is set, r9 is set to 0 */ +}; + +struct exception_fixup { + unsigned long cont; /* continuation point (bit 2: clear r9 if set) */ }; -extern const struct exception_table_entry *search_exception_table (unsigned long addr); +extern struct exception_fixup search_exception_table (unsigned long addr); +extern void handle_exception (struct pt_regs *regs, struct exception_fixup fixup); #endif /* _ASM_IA64_UACCESS_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/ucontext.h linux/include/asm-ia64/ucontext.h --- v2.4.3/linux/include/asm-ia64/ucontext.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ia64/ucontext.h Thu Apr 5 12:51:47 2001 @@ -0,0 +1,12 @@ +#ifndef _ASM_IA64_UCONTEXT_H +#define _ASM_IA64_UCONTEXT_H + +struct ucontext { + struct sigcontext uc_mcontext; +}; + +#define uc_link uc_mcontext.sc_gr[0] /* wrong type; nobody cares */ +#define uc_sigmask uc_mcontext.sc_sigmask +#define uc_stack uc_mcontext.sc_stack + +#endif /* _ASM_IA64_UCONTEXT_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ia64/unwind.h linux/include/asm-ia64/unwind.h --- v2.4.3/linux/include/asm-ia64/unwind.h Mon Oct 9 17:55:01 2000 +++ linux/include/asm-ia64/unwind.h Thu Apr 5 12:51:47 2001 @@ -109,22 +109,6 @@ struct switch_stack *sw); /* - * Prepare to unwind the current task. For this to work, the kernel - * stack identified by REGS must look like this: - * - * // // - * | | - * | kernel stack | - * | | - * +=====================+ - * | struct pt_regs | - * +---------------------+ <--- REGS - * | struct switch_stack | - * +---------------------+ - */ -extern void unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs); - -/* * Prepare to unwind the currently running thread. */ extern void unw_init_running (void (*callback)(struct unw_frame_info *info, void *arg), void *arg); @@ -144,42 +128,42 @@ #define unw_is_intr_frame(info) (((info)->flags & UNW_FLAG_INTERRUPT_FRAME) != 0) -static inline unsigned long +static inline int unw_get_ip (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->ip; return 0; } -static inline unsigned long +static inline int unw_get_sp (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->sp; return 0; } -static inline unsigned long +static inline int unw_get_psp (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->psp; return 0; } -static inline unsigned long +static inline int unw_get_bsp (struct unw_frame_info *info, unsigned long *valp) { *valp = (info)->bsp; return 0; } -static inline unsigned long +static inline int unw_get_cfm (struct unw_frame_info *info, unsigned long *valp) { *valp = *(info)->cfm_loc; return 0; } -static inline unsigned long +static inline int unw_set_cfm (struct unw_frame_info *info, unsigned long val) { *(info)->cfm_loc = val; diff -u --recursive --new-file v2.4.3/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h --- v2.4.3/linux/include/asm-m68k/semaphore.h Mon Jan 31 10:32:53 2000 +++ linux/include/asm-m68k/semaphore.h Tue Apr 17 17:19:31 2001 @@ -8,6 +8,7 @@ #include <linux/linkage.h> #include <linux/wait.h> #include <linux/spinlock.h> +#include <linux/rwsem.h> #include <asm/system.h> #include <asm/atomic.h> @@ -185,201 +186,6 @@ : "memory"); } - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * m68k version by Roman Zippel - */ - -struct rw_semaphore { - atomic_t count; - volatile unsigned char write_bias_granted; - volatile unsigned char read_bias_granted; - volatile unsigned char pad1; - volatile unsigned char pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -extern inline void down_read(struct rw_semaphore *sem) -{ - register struct rw_semaphore *__sem __asm__ ("%a1") = sem; - -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - __asm__ __volatile__( - "| atomic down_read operation\n\t" - "subql #1,%0@\n\t" - "jmi 2f\n" - "1:\n" - ".section .text.lock,\"ax\"\n" - ".even\n" - "2:\n\t" - "pea 1b\n\t" - "jbra __down_read_failed\n" - ".previous" - : /* no outputs */ - : "a" (__sem) - : "memory"); -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ - register struct rw_semaphore *__sem __asm__ ("%a1") = sem; - -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - __asm__ __volatile__( - "| atomic down_write operation\n\t" - "subl %1,%0@\n\t" - "jne 2f\n" - "1:\n" - ".section .text.lock,\"ax\"\n" - ".even\n" - "2:\n\t" - "pea 1b\n\t" - "jbra __down_write_failed\n" - ".previous" - : /* no outputs */ - : "a" (__sem), "id" (RW_LOCK_BIAS) - : "memory"); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -extern inline void __up_read(struct rw_semaphore *sem) -{ - register struct rw_semaphore *__sem __asm__ ("%a1") = sem; - - __asm__ __volatile__( - "| atomic up_read operation\n\t" - "addql #1,%0@\n\t" - "jeq 2f\n" - "1:\n" - ".section .text.lock,\"ax\"\n" - ".even\n" - "2:\n\t" - "pea 1b\n\t" - "jbra __rwsem_wake\n" - ".previous" - : /* no outputs */ - : "a" (__sem) - : "memory"); -} - -extern inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -extern inline void __up_write(struct rw_semaphore *sem) -{ - register struct rw_semaphore *__sem __asm__ ("%a1") = sem; - - __asm__ __volatile__( - "| atomic up_write operation\n\t" - "addl %1,%0@\n\t" - "jcs 2f\n" - "1:\n" - ".section .text.lock,\"ax\"\n" - ".even\n" - "2:\n\t" - "pea 1b\n\t" - "jbra __rwsem_wake\n" - ".previous" - : /* no outputs */ - : "a" (__sem), "id" (RW_LOCK_BIAS) - : "memory"); -} - -extern inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); -} #endif /* __ASSEMBLY__ */ #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/bootinfo.h linux/include/asm-mips/bootinfo.h --- v2.4.3/linux/include/asm-mips/bootinfo.h Tue Jul 11 11:15:02 2000 +++ linux/include/asm-mips/bootinfo.h Fri Apr 13 20:26:07 2001 @@ -1,16 +1,13 @@ -/* $Id: bootinfo.h,v 1.11 2000/03/06 11:14:32 raiko Exp $ - * - * bootinfo.h -- Definition of the Linux/MIPS boot information structure - * - * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse, - * Stoned Elipot and Paul M. Antoine. - * +/* * 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, 1996 by Ralf Baechle, Andreas Busse, + * Stoned Elipot and Paul M. Antoine. */ -#ifndef __ASM_MIPS_BOOTINFO_H -#define __ASM_MIPS_BOOTINFO_H +#ifndef _ASM_BOOTINFO_H +#define _ASM_BOOTINFO_H /* * Values for machgroup @@ -105,8 +102,9 @@ * Valid machtype for group NEC DDB */ #define MACH_NEC_DDB5074 0 /* NEC DDB Vrc-5074 */ +#define MACH_NEC_DDB5476 1 /* NEC DDB Vrc-5476 */ -#define GROUP_NEC_DDB_NAMES { "Vrc-5074" } +#define GROUP_NEC_DDB_NAMES { "Vrc-5074", "Vrc-5476"} /* * Valid machtype for group BAGET diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172.h linux/include/asm-mips/it8172/it8172.h --- v2.4.3/linux/include/asm-mips/it8172/it8172.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8172/it8172.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,406 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller defines. + * + * 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. + */ + +#ifndef __IT8172__H__ +#define __IT8172__H__ + +#include <asm/addrspace.h> + +#define IT8172_BASE 0x18000000 +#define IT8172_PCI_IO_BASE 0x14000000 +#define IT8172_PCI_MEM_BASE 0x10000000 + +// System registers offsets from IT8172_BASE +#define IT_CMFPCR 0x0 +#define IT_DSRR 0x2 +#define IT_PCDCR 0x4 +#define IT_SPLLCR 0x6 +#define IT_CIDR 0x10 +#define IT_CRNR 0x12 +#define IT_CPUTR 0x14 +#define IT_CTCR 0x16 +#define IT_SDPR 0xF0 + +// Power management register offset from IT8172_PCI_IO_BASE +// Power Management Device Standby Register +#define IT_PM_DSR 0x15800 + +#define IT_PM_DSR_TMR0SB 0x0001 +#define IT_PM_DSR_TMR1SB 0x0002 +#define IT_PM_DSR_CIR0SB 0x0004 +#define IT_PM_DSR_CIR1SB 0x0008 +#define IT_PM_DSR_SCR0SB 0x0010 +#define IT_PM_DSR_SCR1SB 0x0020 +#define IT_PM_DSR_PPSB 0x0040 +#define IT_PM_DSR_I2CSB 0x0080 +#define IT_PM_DSR_UARTSB 0x0100 +#define IT_PM_DSR_IDESB 0x0200 +#define IT_PM_DSR_ACSB 0x0400 +#define IT_PM_DSR_M68KSB 0x0800 + +// Power Management PCI Device Software Reset Register +#define IT_PM_PCISR 0x15802 + +#define IT_PM_PCISR_IDESR 0x0001 +#define IT_PM_PCISR_CDMASR 0x0002 +#define IT_PM_PCISR_USBSR 0x0004 +#define IT_PM_PCISR_DMASR 0x0008 +#define IT_PM_PCISR_ACSR 0x0010 +#define IT_PM_PCISR_MEMSR 0x0020 +#define IT_PM_PCISR_68KSR 0x0040 + + +// PCI Configuration address and data register offsets +// from IT8172_BASE +#define IT_CONFADDR 0x4000 +#define IT_BUSNUM_SHF 16 +#define IT_DEVNUM_SHF 11 +#define IT_FUNCNUM_SHF 8 +#define IT_REGNUM_SHF 2 + +#define IT_CONFDATA 0x4004 + +// PCI configuration header common register offsets +#define IT_VID 0x00 +#define IT_DID 0x02 +#define IT_PCICMD 0x04 +#define IT_PCISTS 0x06 +#define IT_RID 0x08 +#define IT_CLASSC 0x09 +#define IT_HEADT 0x0E +#define IT_SERIRQC 0x49 + +// PCI to Internal/LPC Bus Bridge configuration header register offset +#define IT_P2I_BCR 0x4C +#define IT_P2I_D0IOSC 0x50 +#define IT_P2I_D1IOSC 0x54 +#define IT_P2I_D2IOSC 0x58 +#define IT_P2I_D3IOSC 0x5C +#define IT_P2I_D4IOSC 0x60 +#define IT_P2I_D5IOSC 0x64 +#define IT_P2I_D6IOSC 0x68 +#define IT_P2I_D7IOSC 0x6C +#define IT_P2I_D8IOSC 0x70 +#define IT_P2I_D9IOSC 0x74 +#define IT_P2I_D10IOSC 0x78 +#define IT_P2I_D11IOSC 0x7C + +// Memory controller register offsets from IT8172_BASE +#define IT_MC_SDRMR 0x1000 +#define IT_MC_SDRTR 0x1004 +#define IT_MC_MCR 0x1008 +#define IT_MC_SDTYPE 0x100C +#define IT_MC_WPBA 0x1010 +#define IT_MC_WPTA 0x1014 +#define IT_MC_HATR 0x1018 +#define IT_MC_PCICR 0x101C + +// Flash/ROM control register offsets from IT8172_BASE +#define IT_FC_BRCR 0x2000 +#define IT_FC_FCR 0x2004 +#define IT_FC_DCR 0x2008 + +// M68K interface bridge configuration header register offset +#define IT_M68K_MBCSR 0x54 +#define IT_M68K_TMR 0x58 +#define IT_M68K_BCR 0x5C +#define IT_M68K_BSR 0x5D +#define IT_M68K_DTR 0x5F + +// Register offset from IT8172_PCI_IO_BASE +// These registers are accessible through 8172 PCI IO window. + +// INTC +#define IT_INTC_BASE 0x10000 +#define IT_INTC_LBDNIRR 0x10000 +#define IT_INTC_LBDNIMR 0x10002 +#define IT_INTC_LBDNITR 0x10004 +#define IT_INTC_LBDNIAR 0x10006 +#define IT_INTC_LPCNIRR 0x10010 +#define IT_INTC_LPCNIMR 0x10012 +#define IT_INTC_LPCNITR 0x10014 +#define IT_INTC_LPCNIAR 0x10016 +#define IT_INTC_PDNIRR 0x10020 +#define IT_INTC_PDNIMR 0x10022 +#define IT_INTC_PDNITR 0x10024 +#define IT_INTC_PDNIAR 0x10026 +#define IT_INTC_UMNIRR 0x10030 +#define IT_INTC_UMNITR 0x10034 +#define IT_INTC_UMNIAR 0x10036 +#define IT_INTC_TYPER 0x107FE + +// IT8172 PCI device number +#define IT_C2P_DEVICE 0 +#define IT_AUDIO_DEVICE 1 +#define IT_DMAC_DEVICE 1 +#define IT_CDMAC_DEVICE 1 +#define IT_USB_DEVICE 1 +#define IT_P2I_DEVICE 1 +#define IT_IDE_DEVICE 1 +#define IT_M68K_DEVICE 1 + +// IT8172 PCI function number +#define IT_C2P_FUNCION 0 +#define IT_AUDIO_FUNCTION 0 +#define IT_DMAC_FUNCTION 1 +#define IT_CDMAC_FUNCTION 2 +#define IT_USB_FUNCTION 3 +#define IT_P2I_FUNCTION 4 +#define IT_IDE_FUNCTION 5 +#define IT_M68K_FUNCTION 6 + +// IT8172 GPIO +#define IT_GPADR 0x13800 +#define IT_GPBDR 0x13808 +#define IT_GPCDR 0x13810 +#define IT_GPACR 0x13802 +#define IT_GPBCR 0x1380A +#define IT_GPCCR 0x13812 +#define IT_GPAICR 0x13804 +#define IT_GPBICR 0x1380C +#define IT_GPCICR 0x13814 +#define IT_GPAISR 0x13806 +#define IT_GPBISR 0x1380E +#define IT_GPCISR 0x13816 +#define IT_GCR 0x13818 + +// IT8172 RTC +#define IT_RTC_BASE 0x14800 +#define IT_RTC_RIR0 0x00 +#define IT_RTC_RTR0 0x01 +#define IT_RTC_RIR1 0x02 +#define IT_RTC_RTR1 0x03 +#define IT_RTC_RIR2 0x04 +#define IT_RTC_RTR2 0x05 +#define IT_RTC_RCTR 0x08 +#define IT_RTC_RA 0x0A +#define IT_RTC_RB 0x0B +#define IT_RTC_RC 0x0C +#define IT_RTC_RD 0x0D + +#define RTC_SEC_INDEX 0x00 +#define RTC_MIN_INDEX 0x02 +#define RTC_HOUR_INDEX 0x04 +#define RTC_DAY_INDEX 0x06 +#define RTC_DATE_INDEX 0x07 +#define RTC_MONTH_INDEX 0x08 +#define RTC_YEAR_INDEX 0x09 + +// IT8172 internal device registers +#define IT_TIMER_BASE 0x10800 +#define IT_CIR0_BASE 0x11000 +#define IT_UART_BASE 0x11800 +#define IT_SCR0_BASE 0x12000 +#define IT_SCR1_BASE 0x12800 +#define IT_PP_BASE 0x13000 +#define IT_I2C_BASE 0x14000 +#define IT_CIR1_BASE 0x15000 + +// IT8172 Smart Card Reader offsets from IT_SCR*_BASE +#define IT_SCR_SFR 0x08 +#define IT_SCR_SCDR 0x09 + +// IT8172 IT_SCR_SFR bit definition & mask +#define IT_SCR_SFR_GATE_UART 0x40 +#define IT_SCR_SFR_GATE_UART_BIT 6 +#define IT_SCR_SFR_GATE_UART_OFF 0 +#define IT_SCR_SFR_GATE_UART_ON 1 +#define IT_SCR_SFR_FET_CHARGE 0x30 +#define IT_SCR_SFR_FET_CHARGE_BIT 4 +#define IT_SCR_SFR_FET_CHARGE_3_3_US 3 +#define IT_SCR_SFR_FET_CHARGE_13_US 2 +#define IT_SCR_SFR_FET_CHARGE_53_US 1 +#define IT_SCR_SFR_FET_CHARGE_213_US 0 +#define IT_SCR_SFR_CARD_FREQ 0x0C +#define IT_SCR_SFR_CARD_FREQ_BIT 2 +#define IT_SCR_SFR_CARD_FREQ_STOP 3 +#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ 0 +#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ 2 +#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ 1 +#define IT_SCR_SFR_FET_ACTIVE 0x02 +#define IT_SCR_SFR_FET_ACTIVE_BIT 1 +#define IT_SCR_SFR_FET_ACTIVE_INVERT 0 +#define IT_SCR_SFR_FET_ACTIVE_NONINVERT 1 +#define IT_SCR_SFR_ENABLE 0x01 +#define IT_SCR_SFR_ENABLE_BIT 0 +#define IT_SCR_SFR_ENABLE_OFF 0 +#define IT_SCR_SFR_ENABLE_ON 1 + +// IT8172 IT_SCR_SCDR bit definition & mask +#define IT_SCR_SCDR_RESET_MODE 0x80 +#define IT_SCR_SCDR_RESET_MODE_BIT 7 +#define IT_SCR_SCDR_RESET_MODE_ASYNC 0 +#define IT_SCR_SCDR_RESET_MODE_SYNC 1 +#define IT_SCR_SCDR_DIVISOR 0x7F +#define IT_SCR_SCDR_DIVISOR_BIT 0 +#define IT_SCR_SCDR_DIVISOR_STOP_VAL_1 0x00 +#define IT_SCR_SCDR_DIVISOR_STOP_VAL_2 0x01 +#define IT_SCR_SCDR_DIVISOR_STOP_VAL_3 0x7F + +// IT8172 DMA +#define IT_DMAC_BASE 0x16000 +#define IT_DMAC_BCAR0 0x00 +#define IT_DMAC_BCAR1 0x04 +#define IT_DMAC_BCAR2 0x08 +#define IT_DMAC_BCAR3 0x0C +#define IT_DMAC_BCCR0 0x02 +#define IT_DMAC_BCCR1 0x06 +#define IT_DMAC_BCCR2 0x0a +#define IT_DMAC_BCCR3 0x0e +#define IT_DMAC_CR 0x10 +#define IT_DMAC_SR 0x12 +#define IT_DMAC_ESR 0x13 +#define IT_DMAC_RQR 0x14 +#define IT_DMAC_MR 0x16 +#define IT_DMAC_EMR 0x17 +#define IT_DMAC_MKR 0x18 +#define IT_DMAC_PAR0 0x20 +#define IT_DMAC_PAR1 0x22 +#define IT_DMAC_PAR2 0x24 +#define IT_DMAC_PAR3 0x26 + +// IT8172 IDE +#define IT_IDE_BASE 0x17800 +#define IT_IDE_STATUS 0x1F7 + +// IT8172 Audio Controller +#define IT_AC_BASE 0x17000 +#define IT_AC_PCMOV 0x00 +#define IT_AC_FMOV 0x02 +#define IT_AC_I2SV 0x04 +#define IT_AC_DRSS 0x06 +#define IT_AC_PCC 0x08 +#define IT_AC_PCDL 0x0A +#define IT_AC_PCB1STA 0x0C +#define IT_AC_PCB2STA 0x10 +#define IT_AC_CAPCC 0x14 +#define IT_AC_CAPCDL 0x16 +#define IT_AC_CAPB1STA 0x18 +#define IT_AC_CAPB2STA 0x1C +#define IT_AC_CODECC 0x22 +#define IT_AC_I2SMC 0x24 +#define IT_AC_VS 0x26 +#define IT_AC_SRCS 0x28 +#define IT_AC_CIRCP 0x2A +#define IT_AC_CIRDP 0x2C +#define IT_AC_TM 0x4A +#define IT_AC_PFDP 0x4C +#define IT_AC_GC 0x54 +#define IT_AC_IMC 0x56 +#define IT_AC_ISC 0x5B +#define IT_AC_OPL3SR 0x68 +#define IT_AC_OPL3DWDR 0x69 +#define IT_AC_OPL3AB1W 0x6A +#define IT_AC_OPL3DW 0x6B +#define IT_AC_BPDC 0x70 + +// Audio : IT_AC_PCC bit definition & mask +#define PCC_SM 0x8000 +#define PCC_SM_BIT 15 +#define PCC_SM_STEREO 1 +#define PCC_SM_MONO 0 + +#define PCC_DF 0x4000 +#define PCC_DF_BIT 14 +#define PCC_DF_8 0 +#define PCC_DF_16 1 + +#define PCC_CF 0x3000 +#define PCC_CF_BIT 12 +#define PCC_CF_2 0 +#define PCC_CF_4 1 +#define PCC_CF_6 2 + +#define PCC_SR 0x0F00 +#define PCC_SR_BIT 8 +#define PCC_SR_5500 0 +#define PCC_SR_8000 1 +#define PCC_SR_9600 2 +#define PCC_SR_11025 3 +#define PCC_SR_16000 4 +#define PCC_SR_19200 5 +#define PCC_SR_22050 6 +#define PCC_SR_32000 7 +#define PCC_SR_38400 8 +#define PCC_SR_44100 9 +#define PCC_SR_48000 10 + +#define PCC_CSP 0x0080 +#define PCC_CSP_BIT 7 +#define PCC_CSP_STOP 0 +#define PCC_CSP_STOP_NOW 1 + +#define PCC_CP 0x0040 +#define PCC_CP_BIT 6 +#define PCC_CP_NORMAL 0 +#define PCC_CP_PAUSE 1 + +#define PCC_CA 0x0020 +#define PCC_CA_BIT 5 +#define PCC_CA_NO_START 0 +#define PCC_CA_START 1 + +#define PCC_CB2L 0x0004 +#define PCC_CB2L_BIT 2 +#define PCC_CB2L_NO 0 +#define PCC_CB2L_YES 1 + +#define PCC_CB1L 0x0002 +#define PCC_CB1L_BIT 1 +#define PCC_CB1L_NO 0 +#define PCC_CB1L_YES 1 + +#define PCC_DE 0x0001 +#define PCC_DE_BIT 0 +#define PCC_DE_NOT_EMPTY 0 +#define PCC_DE_EMPTY 1 + +// IT8172 Timer +#define IT_TIMER_BASE 0x10800 +#define TIMER_TCVR0 0x00 +#define TIMER_TRVR0 0x02 +#define TIMER_TCR0 0x04 +#define TIMER_TIRR 0x06 +#define TIMER_TCVR1 0x08 +#define TIMER_TRVR1 0x0A +#define TIMER_TCR1 0x0C +#define TIMER_TIDR 0x0E + + +#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data +#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) + +#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data +#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) + +#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data +#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_cir.h linux/include/asm-mips/it8172/it8172_cir.h --- v2.4.3/linux/include/asm-mips/it8172/it8172_cir.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8172/it8172_cir.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,140 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 Consumer IR port defines. + * + * 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. + */ + +#define NUM_CIR_PORTS 2 + +/* Master Control Register */ +#define CIR_RESET 0x1 +#define CIR_FIFO_CLEAR 0x2 +#define CIR_SET_FIFO_TL(x) (((x)&0x3)<<2) +#define CIR_ILE 0x10 +#define CIR_ILSEL 0x20 + +/* Interrupt Enable Register */ +#define CIR_TLDLIE 0x1 +#define CIR_RDAIE 0x2 +#define CIR_RFOIE 0x4 +#define CIR_IEC 0x80 + +/* Interrupt Identification Register */ +#define CIR_TLDLI 0x1 +#define CIR_RDAI 0x2 +#define CIR_RFOI 0x4 +#define CIR_NIP 0x80 + +/* Carrier Frequency Register */ +#define CIR_SET_CF(x) ((x)&0x1f) + #define CFQ_38_480 0xB /* 38 KHz low, 480 KHz high */ +#define CIR_HCFS 0x20 + #define CIR_SET_HS(x) (((x)&0x1)<<5) + + +/* Receiver Control Register */ +#define CIR_SET_RXDCR(x) ((x)&0x7) +#define CIR_RXACT 0x8 +#define CIR_RXEND 0x10 +#define CIR_RDWOS 0x20 + #define CIR_SET_RDWOS(x) (((x)&0x1)<<5) +#define CIR_RXEN 0x80 + +/* Transmitter Control Register */ +#define CIR_SET_TXMPW(x) ((x)&0x7) +#define CIR_SET_TXMPM(x) (((x)&0x3)<<3) +#define CIR_TXENDF 0x20 +#define CIR_TXRLE 0x40 + +/* Receiver FIFO Status Register */ +#define CIR_RXFBC_MASK 0x3f +#define CIR_RXFTO 0x80 + +/* Wakeup Code Length Register */ +#define CIR_SET_WCL ((x)&0x3f) +#define CIR_WCL_MASK(x) ((x)&0x3f) + +/* Wakeup Power Control/Status Register */ +#define CIR_BTMON 0x2 +#define CIR_CIRON 0x4 +#define CIR_RCRST 0x10 +#define CIR_WCRST 0x20 + +struct cir_port { + int port; + unsigned short baud_rate; + unsigned char fifo_tl; + unsigned char cfq; + unsigned char hcfs; + unsigned char rdwos; + unsigned char rxdcr; +}; + +struct it8172_cir_regs { + unsigned char dr; /* data */ + char pad; + unsigned char mstcr; /* master control */ + char pad1; + unsigned char ier; /* interrupt enable */ + char pad2; + unsigned char iir; /* interrupt identification */ + char pad3; + unsigned char cfr; /* carrier frequency */ + char pad4; + unsigned char rcr; /* receiver control */ + char pad5; + unsigned char tcr; /* transmitter control */ + char pad6; + char pad7; + char pad8; + unsigned char bdlr; /* baud rate divisor low byte */ + char pad9; + unsigned char bdhr; /* baud rate divisor high byte */ + char pad10; + unsigned char tfsr; /* tx fifo byte count */ + char pad11; + unsigned char rfsr; /* rx fifo status */ + char pad12; + unsigned char wcl; /* wakeup code length */ + char pad13; + unsigned char wcr; /* wakeup code read/write */ + char pad14; + unsigned char wps; /* wakeup power control/status */ +}; + +int cir_port_init(struct cir_port *cir); +extern void clear_fifo(struct cir_port *cir); +extern void enable_receiver(struct cir_port *cir); +extern void disable_receiver(struct cir_port *cir); +extern void enable_rx_demodulation(struct cir_port *cir); +extern void disable_rx_demodulation(struct cir_port *cir); +extern void set_rx_active(struct cir_port *cir); +extern void int_enable(struct cir_port *cir); +extern void rx_int_enable(struct cir_port *cir); +extern char get_int_status(struct cir_port *cir); +extern int cir_get_rx_count(struct cir_port *cir); +extern char cir_read_data(struct cir_port *cir); diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_dbg.h linux/include/asm-mips/it8172/it8172_dbg.h --- v2.4.3/linux/include/asm-mips/it8172/it8172_dbg.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8172/it8172_dbg.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,38 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Function prototypes for low level uart routines to + * directly access a 16550 uart. + * + * 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 <linux/types.h> + +extern void putch(const unsigned char c); +extern void puts(unsigned char *cp); +extern void fputs(unsigned char *cp); +extern void put64(uint64_t ul); +extern void put32(unsigned u); diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_int.h linux/include/asm-mips/it8172/it8172_int.h --- v2.4.3/linux/include/asm-mips/it8172/it8172_int.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8172/it8172_int.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,146 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * ITE 8172 Interrupt Numbering + * + * 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. + */ + +#ifndef _MIPS_ITEINT_H +#define _MIPS_ITEINT_H + +/* + * Here's the "strategy": + * We number the LPC serial irqs from 0 to 15, + * the local bus irqs from 16 to 31, + * the pci dev register interrupts from 32 to 47, + * and the non-maskable ints from 48 to 53. + */ + +#define IT8172_LPC_IRQ_BASE 0 /* first LPC int number */ +#define IT8172_SERIRQ_0 (IT8172_LPC_IRQ_BASE + 0) +#define IT8172_SERIRQ_1 (IT8172_LPC_IRQ_BASE + 1) +#define IT8172_SERIRQ_2 (IT8172_LPC_IRQ_BASE + 2) +#define IT8172_SERIRQ_3 (IT8172_LPC_IRQ_BASE + 3) +#define IT8172_SERIRQ_4 (IT8172_LPC_IRQ_BASE + 4) +#define IT8172_SERIRQ_5 (IT8172_LPC_IRQ_BASE + 5) +#define IT8172_SERIRQ_6 (IT8172_LPC_IRQ_BASE + 6) +#define IT8172_SERIRQ_7 (IT8172_LPC_IRQ_BASE + 7) +#define IT8172_SERIRQ_8 (IT8172_LPC_IRQ_BASE + 8) +#define IT8172_SERIRQ_9 (IT8172_LPC_IRQ_BASE + 9) +#define IT8172_SERIRQ_10 (IT8172_LPC_IRQ_BASE + 10) +#define IT8172_SERIRQ_11 (IT8172_LPC_IRQ_BASE + 11) +#define IT8172_SERIRQ_12 (IT8172_LPC_IRQ_BASE + 12) +#define IT8172_SERIRQ_13 (IT8172_LPC_IRQ_BASE + 13) +#define IT8172_SERIRQ_14 (IT8172_LPC_IRQ_BASE + 14) +#define IT8172_SERIRQ_15 (IT8172_LPC_IRQ_BASE + 15) + +#define IT8172_LB_IRQ_BASE 16 /* first local bus int number */ +#define IT8172_PPR_IRQ (IT8172_LB_IRQ_BASE + 0) /* parallel port */ +#define IT8172_TIMER0_IRQ (IT8172_LB_IRQ_BASE + 1) +#define IT8172_TIMER1_IRQ (IT8172_LB_IRQ_BASE + 2) +#define IT8172_I2C_IRQ (IT8172_LB_IRQ_BASE + 3) +#define IT8172_GPIO_IRQ (IT8172_LB_IRQ_BASE + 4) +#define IT8172_CIR0_IRQ (IT8172_LB_IRQ_BASE + 5) +#define IT8172_CIR1_IRQ (IT8172_LB_IRQ_BASE + 6) +#define IT8172_UART_IRQ (IT8172_LB_IRQ_BASE + 7) +#define IT8172_SCR0_IRQ (IT8172_LB_IRQ_BASE + 8) +#define IT8172_SCR1_IRQ (IT8172_LB_IRQ_BASE + 9) +#define IT8172_RTC_IRQ (IT8172_LB_IRQ_BASE + 10) +#define IT8172_IOCHK_IRQ (IT8172_LB_IRQ_BASE + 11) +/* 12 - 15 reserved */ + +/* + * Note here that the pci dev registers includes bits for more than + * just the pci devices. + */ +#define IT8172_PCI_DEV_IRQ_BASE 32 /* first pci dev irq */ +#define IT8172_AC97_IRQ (IT8172_PCI_DEV_IRQ_BASE + 0) +#define IT8172_MC68K_IRQ (IT8172_PCI_DEV_IRQ_BASE + 1) +#define IT8172_IDE_IRQ (IT8172_PCI_DEV_IRQ_BASE + 2) +#define IT8172_USB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 3) +#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4) +#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5) +#define IT8172_PCI_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 6) +#define IT8172_PCI_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 7) +#define IT8172_PCI_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 8) +#define IT8172_PCI_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 9) +#define IT8172_S_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 10) +#define IT8172_S_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 11) +#define IT8172_S_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 12) +#define IT8172_S_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 13) +#define IT8172_CDMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 14) +#define IT8172_DMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 15) + +#define IT8172_NMI_IRQ_BASE 48 +#define IT8172_SER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 0) +#define IT8172_PCI_NMI_IRQ (IT8172_NMI_IRQ_BASE + 1) +#define IT8172_RTC_NMI_IRQ (IT8172_NMI_IRQ_BASE + 2) +#define IT8172_CPUIF_NMI_IRQ (IT8172_NMI_IRQ_BASE + 3) +#define IT8172_PMER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 4) +#define IT8172_POWER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 5) + +/* Finally, let's move over here the mips cpu timer interrupt. + * This is more or less strictly for statistics. + */ +#define MIPS_CPU_TIMER_IRQ (IT8172_NMI_IRQ_BASE + 6) + +#define IT8172_INT_END MIPS_CPU_TIMER_IRQ + +/* + * IT8172 Interrupt Controller Registers + */ +struct it8172_intc_regs { + volatile unsigned short lb_req; /* offset 0 */ + volatile unsigned short lb_mask; + volatile unsigned short lb_trigger; + volatile unsigned short lb_level; + unsigned char pad0[8]; + + volatile unsigned short lpc_req; /* offset 0x10 */ + volatile unsigned short lpc_mask; + volatile unsigned short lpc_trigger; + volatile unsigned short lpc_level; + unsigned char pad1[8]; + + volatile unsigned short pci_req; /* offset 0x20 */ + volatile unsigned short pci_mask; + volatile unsigned short pci_trigger; + volatile unsigned short pci_level; + unsigned char pad2[8]; + + volatile unsigned short nmi_req; /* offset 0x30 */ + volatile unsigned short nmi_mask; + volatile unsigned short nmi_trigger; + volatile unsigned short nmi_level; + unsigned char pad3[6]; + + volatile unsigned short nmi_redir; /* offset 0x3E */ + unsigned char pad4[0xBE]; + + volatile unsigned short intstatus; /* offset 0xFE */ +}; + +#endif /* _MIPS_ITEINT_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_lpc.h linux/include/asm-mips/it8172/it8172_lpc.h --- v2.4.3/linux/include/asm-mips/it8172/it8172_lpc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8172/it8172_lpc.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,29 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller defines. + * + * 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. + */ diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8172/it8172_pci.h linux/include/asm-mips/it8172/it8172_pci.h --- v2.4.3/linux/include/asm-mips/it8172/it8172_pci.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8172/it8172_pci.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,108 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller specific pci defines. + * + * 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. + */ + +#ifndef _8172PCI_H_ +#define _8172PCI_H_ + +// PCI configuration space Type0 +#define PCI_IDREG 0x00 +#define PCI_CMDSTSREG 0x04 +#define PCI_CLASSREG 0x08 +#define PCI_BHLCREG 0x0C +#define PCI_BASE1REG 0x10 +#define PCI_BASE2REG 0x14 +#define PCI_BASE3REG 0x18 +#define PCI_BASE4REG 0x1C +#define PCI_BASE5REG 0x20 +#define PCI_BASE6REG 0x24 +#define PCI_ROMBASEREG 0x30 +#define PCI_INTRREG 0x3C + +// PCI configuration space Type1 +#define PCI_BUSNOREG 0x18 + +#define IT_PCI_VENDORID(x) ((x) & 0xFFFF) +#define IT_PCI_DEVICEID(x) (((x)>>16) & 0xFFFF) + +// Command register +#define PCI_CMD_IOEN 0x00000001 +#define PCI_CMD_MEMEN 0x00000002 +#define PCI_CMD_BUSMASTER 0x00000004 +#define PCI_CMD_SPCYCLE 0x00000008 +#define PCI_CMD_WRINV 0x00000010 +#define PCI_CMD_VGASNOOP 0x00000020 +#define PCI_CMD_PERR 0x00000040 +#define PCI_CMD_WAITCTRL 0x00000080 +#define PCI_CMD_SERR 0x00000100 +#define PCI_CMD_FAST_BACKTOBACK 0x00000200 + +// Status register +#define PCI_STS_66MHZ 0x00200000 +#define PCI_STS_SUPPORT_UDF 0x00400000 +#define PCI_STS_FAST_BACKTOBACK 0x00800000 +#define PCI_STS_DATA_PERR 0x01000000 +#define PCI_STS_DEVSEL0 0x02000000 +#define PCI_STS_DEVSEL1 0x04000000 +#define PCI_STS_SIG_TGTABORT 0x08000000 +#define PCI_STS_RCV_TGTABORT 0x10000000 +#define PCI_STS_RCV_MSTABORT 0x20000000 +#define PCI_STS_SYSERR 0x40000000 +#define PCI_STS_DETCT_PERR 0x80000000 + +#define IT_PCI_CLASS(x) (((x)>>24) & 0xFF) +#define IT_PCI_SUBCLASS(x) (((x)>>16) & 0xFF) +#define IT_PCI_INTERFACE(x) (((x)>>8) & 0xFF) +#define IT_PCI_REVISION(x) ((x) & 0xFF) + +// PCI class code +#define PCI_CLASS_BRIDGE 0x06 + +// bridge subclass +#define PCI_SUBCLASS_BRIDGE_HOST 0x00 +#define PCI_SUBCLASS_BRIDGE_PCI 0x04 + +// BHLCREG +#define IT_PCI_BIST(x) (((x)>>24) & 0xFF) +#define IT_PCI_HEADERTYPE(x) (((x)>>16) & 0xFF) +#define IT_PCI_LATENCYTIMER(x) (((x)>>8) & 0xFF) +#define IT_PCI_CACHELINESIZE(x) ((x) & 0xFF) + +#define PCI_MULTIFUNC 0x80 + +// INTRREG +#define IT_PCI_MAXLAT(x) (((x)>>24) & 0xFF) +#define IT_PCI_MINGNT(x) (((x)>>16) & 0xFF) +#define IT_PCI_INTRPIN(x) (((x)>>8) & 0xFF) +#define IT_PCI_INTRLINE(x) ((x) & 0xFF) + +#define PCI_VENDOR_NEC 0x1033 +#define PCI_VENDOR_DEC 0x1101 + +#endif // _8172PCI_H_ diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/it8712.h linux/include/asm-mips/it8712.h --- v2.4.3/linux/include/asm-mips/it8712.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips/it8712.h Fri Apr 13 20:26:07 2001 @@ -0,0 +1,28 @@ + +#ifndef __IT8712_H__ +#define __IT8712_H__ + +#define LPC_BASE_ADDR 0x14000000 + +// MB PnP configuration register +#define LPC_KEY_ADDR 0x1400002E +#define LPC_DATA_ADDR 0x1400002F + +// Device LDN +#define LDN_SERIAL1 0x01 +#define LDN_SERIAL2 0x02 +#define LDN_PARALLEL 0x03 +#define LDN_KEYBOARD 0x05 +#define LDN_MOUSE 0x06 + +#define IT8712_UART1_PORT 0x3F8 +#define IT8712_UART2_PORT 0x2F8 + +#ifndef ASM_ONLY + +void LPCSetConfig(char LdnNumber, char Index, char data); +char LPCGetConfig(char LdnNumber, char Index); + +#endif + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h --- v2.4.3/linux/include/asm-mips/keyboard.h Sun Jul 9 22:18:15 2000 +++ linux/include/asm-mips/keyboard.h Fri Apr 13 20:26:07 2001 @@ -45,7 +45,7 @@ void (*kbd_request_region)(void); int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *)); - /* PSaux driver resource managment */ + /* PSaux driver resource management */ int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *)); void (*aux_free_irq)(void); diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/mipsregs.h linux/include/asm-mips/mipsregs.h --- v2.4.3/linux/include/asm-mips/mipsregs.h Sun Jul 9 22:18:15 2000 +++ linux/include/asm-mips/mipsregs.h Fri Apr 13 20:26:07 2001 @@ -292,7 +292,7 @@ /* * Bitfields and bit numbers in the coprocessor 0 cause register. * - * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation. + * Refer to your MIPS R4xx0 manual, chapter 5 for explanation. */ #define CAUSEB_EXCCODE 2 #define CAUSEF_EXCCODE (31 << 2) diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h --- v2.4.3/linux/include/asm-mips/pci.h Thu Jun 22 07:17:16 2000 +++ linux/include/asm-mips/pci.h Fri Apr 13 20:26:07 2001 @@ -40,7 +40,7 @@ #include <linux/string.h> #include <asm/io.h> -#ifdef CONFIG_DDB5074 +#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476)) #undef PCIBIOS_MIN_IO #undef PCIBIOS_MIN_MEM #define PCIBIOS_MIN_IO 0x0100000 diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h --- v2.4.3/linux/include/asm-mips/processor.h Sat Dec 30 09:35:40 2000 +++ linux/include/asm-mips/processor.h Fri Apr 13 20:26:07 2001 @@ -98,15 +98,20 @@ #define NUM_FPU_REGS 32 struct mips_fpu_hard_struct { - unsigned int fp_regs[NUM_FPU_REGS]; + double fp_regs[NUM_FPU_REGS]; unsigned int control; -} __attribute__((aligned(8))); +}; /* - * FIXME: no fpu emulator yet (but who cares anyway?) + * It would be nice to add some more fields for emulator statistics, but there + * are a number of fixed offsets in offset.h and elsewhere that would have to + * be recalculated by hand. So the additional information will be private to + * the FPU emulator for now. See asm-mips/fpu_emulator.h. */ +typedef u64 fpureg_t; struct mips_fpu_soft_struct { - long dummy; + fpureg_t regs[NUM_FPU_REGS]; + unsigned int sr; }; union mips_fpu_union { @@ -148,6 +153,21 @@ mm_segment_t current_ds; unsigned long irix_trampoline; /* Wheee... */ unsigned long irix_oldctx; + + /* + * These are really only needed if the full FPU emulator is configured. + * Would be made conditional on MIPS_FPU_EMULATOR if it weren't for the + * fact that having offset.h rebuilt differently for different config + * options would be asking for trouble. + * + * Saved EPC during delay-slot emulation (see math-emu/cp1emu.c) + */ + unsigned long dsemul_epc; + + /* + * Pointer to instruction used to induce address error + */ + unsigned long dsemul_aerpc; }; #endif /* !defined (_LANGUAGE_ASSEMBLY) */ @@ -176,7 +196,12 @@ /* \ * For now the default is to fix address errors \ */ \ - MF_FIXADE, { 0 }, 0, 0 \ + MF_FIXADE, { 0 }, 0, 0, \ + /* \ + * dsemul_epc and dsemul_aerpc should never be used uninitialized, \ + * but... \ + */ \ + 0 ,0 \ } #ifdef __KERNEL__ diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/semaphore.h linux/include/asm-mips/semaphore.h --- v2.4.3/linux/include/asm-mips/semaphore.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips/semaphore.h Tue Apr 17 17:19:31 2001 @@ -18,6 +18,7 @@ #include <linux/spinlock.h> #include <linux/wait.h> #include <linux/config.h> +#include <linux/rwsem.h> struct semaphore { #ifdef __MIPSEB__ @@ -215,7 +216,7 @@ atomic_t count; /* bit 0 means read bias granted; bit 1 means write bias granted. */ - unsigned granted; + unsigned long granted; /* pedant: long req'd for set_bit */ wait_queue_head_t wait; wait_queue_head_t write_bias_wait; #if WAITQUEUE_DEBUG diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/sgi/sgimc.h linux/include/asm-mips/sgi/sgimc.h --- v2.4.3/linux/include/asm-mips/sgi/sgimc.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips/sgi/sgimc.h Fri Apr 13 20:26:07 2001 @@ -200,7 +200,7 @@ u32 _unused7; volatile u32 dmamode; /* DMA mode config bit settings */ u32 _unused8; - volatile u32 dmacount; /* Zoom and byte count for DMA */ + volatile u32 dmaccount; /* Zoom and byte count for DMA */ u32 _unused9; volatile u32 dmastart; /* Pedal to the metal. */ u32 _unused10; diff -u --recursive --new-file v2.4.3/linux/include/asm-mips/shmiq.h linux/include/asm-mips/shmiq.h --- v2.4.3/linux/include/asm-mips/shmiq.h Tue Dec 16 12:46:13 1997 +++ linux/include/asm-mips/shmiq.h Fri Apr 13 20:26:07 2001 @@ -146,7 +146,7 @@ /* get time since last event */ #define QIOCGETITIME _IOR('Q', 11, time_t) -/* set curent screen */ +/* set current screen */ #define QIOCSETSCRN _IOW('Q',6,int) diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/errno.h linux/include/asm-mips64/errno.h --- v2.4.3/linux/include/asm-mips64/errno.h Sun Feb 4 21:48:46 2001 +++ linux/include/asm-mips64/errno.h Fri Apr 13 20:26:07 2001 @@ -142,7 +142,6 @@ */ #define ENOMEDIUM 159 /* No medium found */ #define EMEDIUMTYPE 160 /* Wrong medium type */ -#define EHASHCOLLISION 125 /* Number of hash collisons exceeds maximum generation counter value. */ #define EDQUOT 1133 /* Quota exceeded */ diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/keyboard.h linux/include/asm-mips64/keyboard.h --- v2.4.3/linux/include/asm-mips64/keyboard.h Mon Feb 28 07:18:20 2000 +++ linux/include/asm-mips64/keyboard.h Fri Apr 13 20:26:07 2001 @@ -44,7 +44,7 @@ void (*kbd_request_region)(void); int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *)); - /* PSaux driver resource managment */ + /* PSaux driver resource management */ int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *)); void (*aux_free_irq)(void); diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/mipsregs.h linux/include/asm-mips64/mipsregs.h --- v2.4.3/linux/include/asm-mips64/mipsregs.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/mipsregs.h Fri Apr 13 20:26:07 2001 @@ -216,7 +216,7 @@ /* * Bitfields and bit numbers in the coprocessor 0 cause register. * - * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation. + * Refer to your MIPS R4xx0 manual, chapter 5 for explanation. */ #define CAUSEB_EXCCODE 2 #define CAUSEF_EXCCODE (31 << 2) diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/mmzone.h linux/include/asm-mips64/mmzone.h --- v2.4.3/linux/include/asm-mips64/mmzone.h Wed Aug 9 13:46:02 2000 +++ linux/include/asm-mips64/mmzone.h Fri Apr 13 20:26:07 2001 @@ -58,7 +58,7 @@ /* * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory - * and returns the the mem_map of that node. + * and returns the mem_map of that node. */ #define ADDR_TO_MAPBASE(kaddr) \ NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr))) diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/pci/bridge.h linux/include/asm-mips64/pci/bridge.h --- v2.4.3/linux/include/asm-mips64/pci/bridge.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/pci/bridge.h Fri Apr 13 20:26:07 2001 @@ -276,7 +276,7 @@ ds:2, /* Data size */ gbr:1, /* GBR enable */ vbpm:1, /* VBPM message */ - error:1, /* Error occured */ + error:1, /* Error occurred */ barr:1, /* Barrier op */ rsvd:8; } berr_st; diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/semaphore.h linux/include/asm-mips64/semaphore.h --- v2.4.3/linux/include/asm-mips64/semaphore.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/semaphore.h Tue Apr 17 17:19:31 2001 @@ -13,6 +13,7 @@ #include <asm/atomic.h> #include <linux/spinlock.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { #ifdef __MIPSEB__ @@ -167,180 +168,6 @@ #endif if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} - -/* - * rw mutexes (should that be mutices? =) -- throw rw spinlocks and - * semaphores together, and this is what we end up with... - * - * The lock is initialized to BIAS. This way, a writer subtracts BIAS ands - * gets 0 for the case of an uncontended lock. Readers decrement by 1 and - * see a positive value when uncontended, negative if there are writers - * waiting (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and lots of processes. - * BIAS must be chosen such that subtracting BIAS once per CPU will result - * in the int remaining negative. In terms of fairness, this should result - * in the lock flopping back and forth between readers and writers under - * heavy use. - * - * Once we start supporting machines with more than 128 CPUs, we should go - * for using a 64bit atomic type instead of 32bit as counter. We shall - * probably go for bias 0x80000000 then, so that single sethi can set it. - * */ - -#define RW_LOCK_BIAS 0x01000000 - -struct rw_semaphore { - atomic_t count; - /* bit 0 means read bias granted; - bit 1 means write bias granted. */ - unsigned long granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ - { ATOMIC_INIT(count), 0, \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) \ - __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) \ - __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) \ - __DECLARE_RWSEM_GENERIC(name, 0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -/* The expensive part is outlined. */ -extern void __down_read(struct rw_semaphore *sem, int count); -extern void __down_write(struct rw_semaphore *sem, int count); -extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers); - -static inline void down_read(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = atomic_dec_return(&sem->count); - if (count < 0) { - __down_read(sem, count); - } - mb(); - -#if WAITQUEUE_DEBUG - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -static inline void down_write(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count) { - __down_write(sem, count); - } - mb(); - -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->granted & 3) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant case is when - there was a writer waiting, and we've bumped the count to 0: we must - wake the writer up. */ - -static inline void up_read(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - - mb(); - count = atomic_inc_return(&sem->count); - if (count == 0) { - __rwsem_wake(sem, 0); - } -} - -/* - * Releasing the writer is easy -- just release it and wake up any sleepers. - */ -static inline void up_write(struct rw_semaphore *sem) -{ - int count; - -#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 - - mb(); - count = atomic_add_return(RW_LOCK_BIAS, &sem->count); - if (count - RW_LOCK_BIAS < 0 && count >= 0) { - /* Only do the wake if we're no longer negative. */ - __rwsem_wake(sem, count); - } } #endif /* _ASM_SEMAPHORE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-mips64/shmiq.h linux/include/asm-mips64/shmiq.h --- v2.4.3/linux/include/asm-mips64/shmiq.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/shmiq.h Fri Apr 13 20:26:07 2001 @@ -153,7 +153,7 @@ /* get time since last event */ #define QIOCGETITIME _IOR('Q', 11, time_t) -/* set curent screen */ +/* set current screen */ #define QIOCSETSCRN _IOW('Q',6,int) diff -u --recursive --new-file v2.4.3/linux/include/asm-parisc/semaphore.h linux/include/asm-parisc/semaphore.h --- v2.4.3/linux/include/asm-parisc/semaphore.h Tue Dec 5 12:29:39 2000 +++ linux/include/asm-parisc/semaphore.h Tue Apr 17 17:19:31 2001 @@ -17,6 +17,7 @@ */ #include <linux/spinlock.h> +#include <linux/rwsem.h> #include <asm/system.h> #include <asm/atomic.h> @@ -133,169 +134,6 @@ #endif if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subl'ing - * BIAS once per CPU will result in the long remaining - * negative. - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned char write_bias_granted; - volatile unsigned char read_bias_granted; - volatile unsigned char pad1; - volatile unsigned char pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define RW_LOCK_BIAS 0x01000000 - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME -extern struct rw_semaphore *__build_read_lock(struct rw_semaphore *sem, const char *what); -extern struct rw_semaphore *__build_write_lock(struct rw_semaphore *sem, const char *what); -#endif - -/* we use FASTCALL convention for the helpers */ -extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem)); -extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem)); -extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); - -extern inline void down_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif -#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME - __build_read_lock(sem, "__down_read_failed"); -#endif -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif -#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME - __build_write_lock(sem, "__down_write_failed"); -#endif -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -extern inline void __up_read(struct rw_semaphore *sem) -{ -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -extern inline void __up_write(struct rw_semaphore *sem) -{ -} - -extern inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -extern inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); } #endif /* _ASM_PARISC_SEMAPHORE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/kmap_types.h linux/include/asm-ppc/kmap_types.h --- v2.4.3/linux/include/asm-ppc/kmap_types.h Sat Nov 11 18:23:10 2000 +++ linux/include/asm-ppc/kmap_types.h Thu Apr 12 12:11:39 2001 @@ -5,6 +5,8 @@ enum km_type { KM_BOUNCE_READ, KM_BOUNCE_WRITE, + KM_SKB_DATA, + KM_SKB_DATA_SOFTIRQ, KM_TYPE_NR }; diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h --- v2.4.3/linux/include/asm-ppc/semaphore.h Fri Mar 23 22:42:31 2001 +++ linux/include/asm-ppc/semaphore.h Tue Apr 17 17:19:31 2001 @@ -14,6 +14,7 @@ #include <asm/atomic.h> #include <asm/system.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -105,99 +106,6 @@ if (atomic_inc_return(&sem->count) <= 0) __up(sem); } - - -/* RW spinlock-based semaphores */ - -struct rw_semaphore -{ - spinlock_t lock; - int rd, wr; - wait_queue_head_t wait; -#if WAITQUEUE_DEBUG - long __magic; -#endif -}; - -#define RW_LOCK_BIAS 2 /* XXX bogus */ -#define __RWSEM_INITIALIZER(name, count) \ -{ \ - SPIN_LOCK_UNLOCKED, \ - (count) == 1, (count) == 0, \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ - __SEM_DEBUG_INIT(name) \ -} - -#define __DECLARE_RWSEM_GENERIC(name, count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name, count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - spin_lock_init(&sem->lock); - sem->rd = sem->wr = 0; - init_waitqueue_head(&sem->wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; -#endif -} - -#ifndef CHECK_MAGIC -#define CHECK_MAGIC(x) -#endif - -extern void down_read_failed(struct rw_semaphore *); -extern void down_write_failed(struct rw_semaphore *); - -extern inline void down_read(struct rw_semaphore *sem) -{ - CHECK_MAGIC(sem->__magic); - - spin_lock_irq(&sem->lock); - if (sem->wr) - down_read_failed(sem); - sem->rd++; - spin_unlock_irq(&sem->lock); -} - -extern inline void down_write(struct rw_semaphore *sem) -{ - CHECK_MAGIC(sem->__magic); - - spin_lock(&sem->lock); - if(sem->rd || sem->wr) - down_write_failed(sem); - sem->wr = 1; - spin_unlock(&sem->lock); -} - -#define up_read(sem) \ - do { \ - unsigned long flags; \ - \ - CHECK_MAGIC((sem)->__magic); \ - \ - spin_lock_irqsave(&(sem)->lock, flags); \ - if (!--(sem)->rd && waitqueue_active(&(sem)->wait)) \ - wake_up(&(sem)->wait); \ - spin_unlock_irqrestore(&(sem)->lock, flags); \ - } while (0) - -#define up_write(sem) \ - do { \ - unsigned long flags; \ - \ - CHECK_MAGIC((sem)->__magic); \ - \ - spin_lock_irqsave(&(sem)->lock, flags); \ - (sem)->wr = 0; \ - if (waitqueue_active(&(sem)->wait)) \ - wake_up(&(sem)->wait); \ - spin_unlock_irqrestore(&(sem)->lock, flags); \ - } while (0) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-ppc/tqm8xx.h linux/include/asm-ppc/tqm8xx.h --- v2.4.3/linux/include/asm-ppc/tqm8xx.h Sat Mar 3 10:52:14 2001 +++ linux/include/asm-ppc/tqm8xx.h Thu Apr 12 12:16:36 2001 @@ -12,6 +12,8 @@ #ifndef __MACH_TQM8xx_DEFS #define __MACH_TQM8xx_DEFS +#include <linux/config.h> + #ifndef __ASSEMBLY__ typedef void (interrupt_handler_t)(void *); diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h --- v2.4.3/linux/include/asm-s390/atomic.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/atomic.h Wed Apr 11 19:02:28 2001 @@ -25,6 +25,15 @@ #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") +#define __CS_LOOP(old, new, ptr, op_val, op_string) \ + __asm__ __volatile__(" l %0,0(%2)\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%3\n" \ + " cs %0,%1,0(%2)\n" \ + " jl 0b" \ + : "=&d" (old), "=&d" (new) \ + : "a" (ptr), "d" (op_val) : "cc" ); + static __inline__ int atomic_read(atomic_t *v) { int retval; @@ -43,150 +52,80 @@ static __inline__ void atomic_add(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " ar 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "ar"); } static __inline__ int atomic_add_return (int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new; } static __inline__ int atomic_add_negative(int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b\n" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval < 0; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new < 0; } static __inline__ void atomic_sub(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " sr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "sr"); } static __inline__ void atomic_inc(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " ahi 1,1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); } static __inline__ int atomic_inc_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new; } static __inline__ int atomic_inc_and_test(volatile atomic_t *v) { - int i; - - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i != 0; + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new != 0; } static __inline__ void atomic_dec(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " ahi 1,-1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); } static __inline__ int atomic_dec_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new; } static __inline__ int atomic_dec_and_test(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i == 0; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new == 0; } static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " nr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (~(mask)) - : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, ~mask, "nr"); } static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,%0\n" - "0: lr 1,0\n" - " or 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, mask, "or"); } /* @@ -199,15 +138,14 @@ int retval; __asm__ __volatile__( - " la 1,%1\n" " lr 0,%2\n" - " cs 0,%3,0(1)\n" + " cs 0,%3,0(%1)\n" " ipm %0\n" " srl %0,28\n" "0:" - : "=&r" (retval), "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "0", "1", "cc"); + : "=&d" (retval) + : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "0", "cc"); return retval; } @@ -218,13 +156,11 @@ atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v) { __asm__ __volatile__( - " la 2,%0\n" - "0: lr 1,%1\n" - " cs 1,%2,0(2)\n" + "0: lr 0,%1\n" + " cs 0,%2,0(%0)\n" " jl 0b\n" - : "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "cc", "1", "2"); + : : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "cc", "0" ); } #define atomic_compare_and_swap_debug(where,from,to) \ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h --- v2.4.3/linux/include/asm-s390/bitops.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/bitops.h Wed Apr 11 19:02:28 2001 @@ -475,9 +475,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -501,9 +501,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -527,9 +527,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h --- v2.4.3/linux/include/asm-s390/ccwcache.h Fri Mar 2 11:12:06 2001 +++ linux/include/asm-s390/ccwcache.h Wed Apr 11 19:02:28 2001 @@ -62,6 +62,7 @@ #define CQR_STATUS_DONE 0x04 /* request is completed successfully */ #define CQR_STATUS_ERROR 0x05 /* request is completed with error */ #define CQR_STATUS_FAILED 0x06 /* request is finally failed */ +#define CQR_STATUS_PENDING 0x07 /* request is waiting for interrupt - ERP only */ #define CQR_FLAGS_CHAINED 0x01 /* request is chained by another (last CCW is TIC) */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/chandev.h linux/include/asm-s390/chandev.h --- v2.4.3/linux/include/asm-s390/chandev.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/chandev.h Wed Apr 11 19:02:28 2001 @@ -66,6 +66,12 @@ unsigned long irqflags, const char *devname, void *dev_id); +/* + * I originally believed this function wouldn't be necessary + * I subsequently found that reprobing failed in certain cases :-(, + * It is just a wrapper for free irq. + */ +void chandev_free_irq(unsigned int irq, void *dev_id); typedef enum { diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/checksum.h linux/include/asm-s390/checksum.h --- v2.4.3/linux/include/asm-s390/checksum.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/checksum.h Wed Apr 11 19:02:28 2001 @@ -36,14 +36,14 @@ extern inline unsigned int csum_partial_inline(const unsigned char * buff, int len, unsigned int sum) { + register_pair rp; + + 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; } @@ -97,14 +97,16 @@ extern inline unsigned short csum_fold(unsigned int sum) { + register_pair rp; + __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"); + " 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); } #endif @@ -117,17 +119,16 @@ extern inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) { + register_pair rp; unsigned long sum; + rp.subreg.even = (unsigned long) iph; + rp.subreg.odd = (unsigned long) ihl*4; __asm__ __volatile__ ( " sr %0,%0\n" /* set sum to zero */ - " 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" (iph), "d" (ihl*4) - : "cc", "2", "3" ); + : "=&d" (sum), "+&a" (rp) : : "cc" ); return csum_fold(sum); } @@ -144,16 +145,21 @@ " alr %0,%1\n" /* sum += saddr */ " brc 12,0f\n" " ahi %0,1\n" /* add carry */ - "0: alr %0,%2\n" /* sum += daddr */ + "0:" + : "+&d" (sum) : "d" (saddr) : "cc" ); + __asm__ __volatile__ ( + " alr %0,%1\n" /* sum += daddr */ " brc 12,1f\n" " ahi %0,1\n" /* add carry */ - "1: alr %0,%3\n" /* sum += (len<<16) + (proto<<8) */ + "1:" + : "+&d" (sum) : "d" (daddr) : "cc" ); + __asm__ __volatile__ ( + " alr %0,%1\n" /* sum += (len<<16) + (proto<<8) */ " brc 12,2f\n" " ahi %0,1\n" /* add carry */ "2:" : "+&d" (sum) - : "d" (saddr), "d" (daddr), - "d" (((unsigned int) len<<16) + (unsigned int) proto) + : "d" (((unsigned int) len<<16) + (unsigned int) proto) : "cc" ); return sum; } diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/cpcmd.h linux/include/asm-s390/cpcmd.h --- v2.4.3/linux/include/asm-s390/cpcmd.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-s390/cpcmd.h Wed Apr 11 19:02:28 2001 @@ -0,0 +1,14 @@ +/* + * 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/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h --- v2.4.3/linux/include/asm-s390/dasd.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/dasd.h Wed Apr 11 19:02:28 2001 @@ -5,11 +5,16 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * History of changes (starts July 2000) + * 02/01/01 added dynamic registration of ioctls */ #ifndef DASD_H #define DASD_H +#undef ERP_DEBUG /* enable debug messages */ +#undef ERP_FULL_ERP /* enable full ERP - experimental code !!!! */ +#define CONFIG_DASD_DYNAMIC + #include <linux/ioctl.h> #include <asm/irq.h> @@ -29,6 +34,10 @@ /* translate blocknumber of partition to absolute */ #define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) +typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args); +int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler); +int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler); + #define DASD_NAME "dasd" #define DASD_PARTN_BITS 2 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) @@ -49,6 +58,10 @@ #define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 #define DASD_FORMAT_DEFAULT_INTENSITY -1 +#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 +#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 +#define DASD_FORMAT_INTENS_INVALIDATE 0x04 +#define DASD_FORMAT_INTENS_CDL 0x08 #ifdef __KERNEL__ #include <linux/version.h> #include <linux/major.h> @@ -135,9 +148,15 @@ typedef struct dasd_devreg_t { devreg_t devreg; /* the devreg itself */ /* build a linked list of devregs, needed for cleanup */ - struct dasd_devreg_t *next; + struct list_head list; } dasd_devreg_t; +typedef struct { + struct list_head list; + int no; + dasd_ioctl_fn_t handler; +} dasd_ioctl_list_t; + typedef enum { dasd_era_fatal = -1, /* no chance to recover */ dasd_era_none = 0, /* don't recover, everything alright */ @@ -168,7 +187,7 @@ int d_major = MAJOR(d_device->kdev); \ int d_minor = MINOR(d_device->kdev); \ printk(d_loglevel PRINTK_HEADER \ - "/dev/%s(%d:%d), 0x%04X on SCH 0x%x:" \ + "/dev/%s(%d:%d),%04X IRQ0x%x:" \ d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ } while(0) @@ -181,6 +200,7 @@ unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ + unsigned int pt_block; /* from which block to read the partn table */ } dasd_sizes_t; /* @@ -193,6 +213,38 @@ ccw_req_t *tail; } dasd_chanq_t; +#define DASD_DEVICE_FORMAT_STRING "Device: %p" +#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_event(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); +#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_exception(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); + +#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" +#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_event(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); +#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_exception(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); + struct dasd_device_t; struct request; @@ -230,7 +282,7 @@ typedef struct dasd_discipline_t { char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ - + int max_blocks; /* maximum number of blocks to be chained */ dasd_ck_id_fn_t id_check; /* to check sense data */ dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ @@ -251,9 +303,13 @@ struct dasd_discipline_t *next; /* used for list of disciplines */ } dasd_discipline_t; +#define DASD_MAJOR_INFO_REGISTERED 1 +#define DASD_MAJOR_INFO_IS_STATIC 2 + typedef struct major_info_t { - struct major_info_t *next; + struct list_head list; struct dasd_device_t **dasd_device; + int flags; struct gendisk gendisk; /* actually contains the major number */ } __attribute__ ((packed)) major_info_t; @@ -278,6 +334,7 @@ struct dasd_chanq_t queue; wait_queue_head_t wait_q; request_queue_t request_queue; + struct timer_list timer; devstat_t dev_status; /* needed ONLY!! for request_irq */ dasd_sizes_t sizes; char name[16]; /* The name of the device in /dev */ @@ -300,7 +357,7 @@ #define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 #define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 #define DASD_DEVICE_LEVEL_ANALYSED 0x08 -#define DASD_DEVICE_LEVEL_PARTITIONED 0x10 +#define DASD_DEVICE_LEVEL_ONLINE 0x10 int dasd_init (void); void dasd_discipline_enq (dasd_discipline_t *); @@ -312,8 +369,12 @@ int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); ccw_req_t *dasd_alloc_request (char *, int, int); void dasd_free_request (ccw_req_t *); -int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *); int dasd_oper_handler (int irq, devreg_t * devreg); +void dasd_schedule_bh (dasd_device_t *); + +debug_info_t *dasd_debug_area; #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/debug.h linux/include/asm-s390/debug.h --- v2.4.3/linux/include/asm-s390/debug.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/debug.h Wed Apr 11 19:02:28 2001 @@ -19,9 +19,8 @@ struct { unsigned long long clock:52; unsigned long long exception:1; - unsigned long long used:1; - unsigned long long unused:1; - unsigned long long cpuid:9; + unsigned long long level:3; + unsigned long long cpuid:8; } fields; unsigned long long stck; @@ -29,6 +28,9 @@ void* caller; } __attribute__((packed)); + +#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + #ifdef __KERNEL__ #include <linux/version.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) @@ -45,7 +47,6 @@ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ #define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ -#define DEBUG_FEATURE_VERSION 1 /* version of debug feature */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ @@ -103,43 +104,98 @@ debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; debug_input_proc_t* input_proc; + void* private_data; }; extern struct debug_view debug_hex_ascii_view; extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +/* do NOT use the _common functions */ + +debug_entry_t* debug_event_common(debug_info_t* id, int level, + const void* data, int length); + +debug_entry_t* debug_exception_common(debug_info_t* id, int level, + const void* data, int length); + +/* Debug Feature API: */ debug_info_t* debug_register(char* name, int pages_index, int nr_areas, - int buf_size); + int buf_size); + void debug_unregister(debug_info_t* id); void debug_set_level(debug_info_t* id, int new_level); -debug_entry_t* debug_event(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_event(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_event(debug_info_t* id, int level, - const char* txt); - -debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_exception(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_exception(debug_info_t* id, int level, - const char* txt); +extern inline debug_entry_t* +debug_event(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_event(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned int)); +} -static inline debug_entry_t * +extern inline debug_entry_t * debug_long_event (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_event(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_event(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,txt,strlen(txt)); } -static inline debug_entry_t * + +extern debug_entry_t * +debug_sprintf_event(debug_info_t* id,int level,char *string,...); + + +extern inline debug_entry_t* +debug_exception(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_exception(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * debug_long_exception (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_exception(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_exception(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,txt,strlen(txt)); } + + +extern debug_entry_t * +debug_sprintf_exception(debug_info_t* id,int level,char *string,...); + int debug_register_view(debug_info_t* id, struct debug_view* view); int debug_unregister_view(debug_info_t* id, struct debug_view* view); diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/delay.h linux/include/asm-s390/delay.h --- v2.4.3/linux/include/asm-s390/delay.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/delay.h Wed Apr 11 19:02:28 2001 @@ -8,7 +8,7 @@ * Derived from "include/asm-i386/delay.h" * Copyright (C) 1993 Linus Torvalds * - * Delay routines calling functions in arch/i386/lib/delay.c + * Delay routines calling functions in arch/s390/lib/delay.c */ #ifndef _S390_DELAY_H diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/div64.h linux/include/asm-s390/div64.h --- v2.4.3/linux/include/asm-s390/div64.h Fri May 12 11:41:44 2000 +++ linux/include/asm-s390/div64.h Wed Apr 11 19:02:28 2001 @@ -1,10 +1,44 @@ #ifndef __S390_DIV64 #define __S390_DIV64 -#define do_div(n,base) ({ \ -int __res; \ -__res = ((unsigned long) n) % (unsigned) base; \ -n = ((unsigned long) n) / (unsigned) base; \ -__res; }) +/* for do_div "base" needs to be smaller than 2^31-1 */ + +#define do_div(n, base) ({ \ + unsigned long long __n = (n); \ + unsigned long __r; \ + \ + asm (" slr 0,0\n" \ + " l 1,%1\n" \ + " srdl 0,1\n" \ + " dr 0,%2\n" \ + " alr 1,1\n" \ + " alr 0,0\n" \ + " lhi 2,1\n" \ + " n 2,%1\n" \ + " alr 0,2\n" \ + " clr 0,%2\n" \ + " jl 0f\n" \ + " slr 0,%2\n" \ + " ahi 1,1\n" \ + "0: st 1,%1\n" \ + " l 1,4+%1\n" \ + " srdl 0,1\n" \ + " dr 0,%2\n" \ + " alr 1,1\n" \ + " alr 0,0\n" \ + " lhi 2,1\n" \ + " n 2,4+%1\n" \ + " alr 0,2\n" \ + " clr 0,%2\n" \ + " jl 1f\n" \ + " slr 0,%2\n" \ + " ahi 1,1\n" \ + "1: st 1,4+%1\n" \ + " lr %0,0" \ + : "=d" (__r), "+m" (__n) \ + : "d" (base) : "0", "1", "2" ); \ + (n) = (__n); \ + __r; \ +}) #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/ebcdic.h linux/include/asm-s390/ebcdic.h --- v2.4.3/linux/include/asm-s390/ebcdic.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/ebcdic.h Wed Apr 11 19:02:28 2001 @@ -24,24 +24,18 @@ extern __inline__ void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr) { - static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 }; + if (nr <= 0) + return; __asm__ __volatile__( - " lr 1,%0\n" - " lr 2,%1\n" - " lr 3,%2\n" - " ahi 2,-256\n" - " jm 1f\n" - "0: tr 0(256,1),0(3)\n" - " ahi 1,256\n" - " ahi 2,-256\n" - " jp 0b\n" - "1: ahi 2,255\n" - " jm 2f\n" - " ex 2,%3\n" - "2:" - : /* no output */ - : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0]) - : "cc", "memory", "1", "2", "3" ); + " bras 1,1f\n" + " tr 0(1,%0),0(%2)\n" + "0: la %0,256(%0)\n" + " tr 0(256,%0),0(%2)\n" + "1: ahi %1,-256\n" + " jp 0b\n" + " ex %1,0(1)" + : "+&a" (addr), "+&a" (nr-1) + : "a" (codepage) : "cc", "memory", "1" ); } #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr) diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/elf.h linux/include/asm-s390/elf.h --- v2.4.3/linux/include/asm-s390/elf.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/elf.h Wed Apr 11 19:02:28 2001 @@ -31,7 +31,8 @@ * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(x) \ - ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/irq.h linux/include/asm-s390/irq.h --- v2.4.3/linux/include/asm-s390/irq.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/irq.h Wed Apr 11 19:02:28 2001 @@ -1,5 +1,5 @@ -#ifndef __irq_h -#define __irq_h +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H #include <linux/config.h> #ifdef __KERNEL__ @@ -19,28 +19,6 @@ extern int enable_irq(unsigned int); /* - * Interrupt controller descriptor. This is all we need - * to describe about the low-level hardware. - */ -struct hw_interrupt_type { - const __u8 *typename; - int (*handle)(unsigned int irq, - int cpu, - struct pt_regs * regs); - int (*enable) (unsigned int irq); - int (*disable)(unsigned int irq); -}; - -/* - * Status: reason for being disabled: somebody has - * done a "disable_irq()" or we must not re-enter the - * already executing irq.. - */ -#define IRQ_INPROGRESS 1 -#define IRQ_DISABLED 2 -#define IRQ_PENDING 4 - -/* * path management control word */ typedef struct { @@ -86,7 +64,7 @@ __u32 pfch : 1; /* prefetch */ __u32 isic : 1; /* initial-status interruption control */ __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* suppress-suspended interruption */ + __u32 ssi : 1; /* supress-suspended interruption */ __u32 zcc : 1; /* zero condition code */ __u32 ectl : 1; /* extended control */ __u32 pno : 1; /* path not operational */ @@ -186,7 +164,7 @@ typedef struct { __u8 cmd_code;/* command code */ - __u8 flags; /* flags, like IDA addressing, etc. */ + __u8 flags; /* flags, like IDA adressing, etc. */ __u16 count; /* byte count */ __u32 cda; /* data address */ } __attribute__ ((packed,aligned(8))) ccw1_t; @@ -456,24 +434,10 @@ typedef int (* adapter_int_handler_t)( __u32 intparm ); -struct s390_irqaction { - io_handler_func_t handler; - unsigned long flags; - const char *name; - devstat_t *dev_id; -}; - -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. - * - * Pad this out to 32 bytes for cache and indexing reasons. - */ typedef struct { - unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ - struct hw_interrupt_type *handler; /* handle/enable/disable functions */ - struct s390_irqaction *action; /* IRQ action list */ + io_handler_func_t handler; /* interrupt handler routine */ + const char *name; /* device name */ + devstat_t *dev_id; /* device status block */ } irq_desc_t; typedef struct { @@ -531,9 +495,8 @@ /* * do_IO() * - * Start a S/390 channel program. When the interrupt arrives - * handle_IRQ_event() is called, which eventually calls the - * IRQ handler, either immediately, delayed (dev-end missing, + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered - * should never occur, as the IRQ (subchannel ID) should be * disabled if no handler is present. Depending on the action @@ -606,8 +569,6 @@ const char *devname, void *dev_id); -extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); - extern int set_cons_dev(int irq); extern int reset_cons_dev(int irq); extern int wait_cons_dev(int irq); @@ -621,16 +582,13 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "STSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) - : "cc", "1" ); + " lr 1,%1\n" + " stsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000), "a" (addr) + : "cc", "1" ); return ccode; } @@ -639,15 +597,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "MSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " msch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -657,12 +612,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - " lgr 1,%1\n" + " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#ifdef CONFIG_ARCH_S390X ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " jg 1b\n" @@ -671,12 +626,12 @@ " .align 8\n" " .quad 0b,2b\n" ".previous" -#else " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#else ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " bras 1,3f\n" @@ -690,7 +645,7 @@ ".previous" #endif : "=d" (ccode) - : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) + : "d" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) : "cc", "1" ); return ccode; } @@ -700,15 +655,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "TSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " tsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -718,10 +670,11 @@ int ccode; __asm__ __volatile__( - "TPI 0(%1)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " tpi 0(%1)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc", "1" ); return ccode; } @@ -731,15 +684,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "SSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " ssch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -749,15 +699,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " rsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -767,15 +714,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "CSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " csch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -785,15 +729,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "HSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " hsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -803,9 +744,9 @@ int ccode; __asm__ __volatile__( - "IAC 1\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" + " iac 1\n" + " ipm %0\n" + " srl %0,28" : "=d" (ccode) : : "cc", "1" ); return ccode; } @@ -815,15 +756,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RCHP\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (chpid) + " lr 1,%1\n" + " rchp\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (chpid) : "cc", "1" ); return ccode; } @@ -850,16 +788,16 @@ __asm__ __volatile__( #ifdef CONFIG_ARCH_S390X - "SAM31\n\t" - "DIAG %1,0,0x210\n\t" - "SAM64\n\t" -#else - "LR 1,%1\n\t" - ".long 0x83110210\n\t" -#endif - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " sam31\n" + " diag %1,0,0x210\n" + " sam64\n" +#else + " diag %1,0,0x210\n" +#endif + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc" ); return ccode; } @@ -885,15 +823,9 @@ static inline void irq_enter(int cpu, unsigned int irq) { hardirq_enter(cpu); -#ifdef CONFIG_ARCH_S390X while (atomic_read(&global_irq_lock) != 0) { eieio(); } -#else - while (test_bit(0,&global_irq_lock)) { - eieio(); - } -#endif } static inline void irq_exit(int cpu, unsigned int irq) @@ -957,6 +889,9 @@ spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags) #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) + +#define touch_nmi_watchdog() do { } while(0) + #endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/irqextras390.h linux/include/asm-s390/irqextras390.h --- v2.4.3/linux/include/asm-s390/irqextras390.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/irqextras390.h Wed Dec 31 16:00:00 1969 @@ -1,151 +0,0 @@ -/* - * include/asm-s390/irqextras390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#ifndef __irqextras390_h -#define __irqextras390_h - -/* - irqextras390.h by D.J. Barrow - if you are a bitfield fan & are paranoid that ansi dosen't - give hard definitions about the size of an int or long you might - prefer these definitions as an alternative. - -*/ - -#include <linux/types.h> - -typedef struct -{ - unsigned key:4; - unsigned s:1; - unsigned l:1; - unsigned cc:2; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - unsigned z:1; - unsigned e:1; - unsigned n:1; - unsigned zero:1; - - unsigned fc_start:1; - unsigned fc_halt:1; - unsigned fc_clear:1; - - unsigned ac_resume_pending:1; - unsigned ac_start_pending:1; - unsigned ac_halt_pending:1; - unsigned ac_clear_pending:1; - unsigned ac_subchannel_active:1; - unsigned ac_device_active:1; - unsigned ac_suspended:1; - - unsigned sc_alert:1; - unsigned sc_intermediate:1; - unsigned sc_primary:1; - unsigned sc_seconary:1; - unsigned sc_status_pending:1; - - __u32 ccw_address; - - unsigned dev_status_attention:1; - unsigned dev_status_modifier:1; - unsigned dev_status_control_unit_end:1; - unsigned dev_status_busy:1; - unsigned dev_status_channel_end:1; - unsigned dev_status_device_end:1; - unsigned dev_status_unit_check:1; - unsigned dev_status_unit_exception:1; - - unsigned sch_status_program_cont_int:1; - unsigned sch_status_incorrect_length:1; - unsigned sch_status_program_check:1; - unsigned sch_status_protection_check:1; - unsigned sch_status_channel_data_check:1; - unsigned sch_status_channel_control_check:1; - unsigned sch_status_interface_control_check:1; - unsigned sch_status_chaining_check:1; - - __u16 byte_count; -} scsw_bits_t __attribute__((packed)); - -typedef struct -{ - __u32 flags; - __u32 ccw_address; - __u8 dev_status; - __u8 sch_status; - __u16 byte_count; -} scsw_words_t __attribute__((packed)); - -typedef struct -{ - __u8 cmd_code; - - unsigned cd:1; - unsigned cc:1; - unsigned sli:1; - unsigned skip:1; - unsigned pci:1; - unsigned ida:1; - unsigned s:1; - unsigned res1:1; - - __u16 count; - - __u32 ccw_data_address; -} ccw1_bits_t __attribute__((packed,aligned(8))); - -typedef struct -{ - __u32 interruption_parm; - unsigned key:4; - unsigned s:1; - unsigned res1:3; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - __u8 lpm; - unsigned l:1; - unsigned res2:7; - ccw1_bits_t *ccw_program_address; -} orb_bits_t __attribute__((packed)); - -void fixchannelprogram(orb_bits_t *orbptr); -void fixccws(ccw1_bits_t *ccwptr); -enum -{ - ccw_write=0x1, - ccw_read=0x2, - ccw_read_backward=0xc, - ccw_control=0x3, - ccw_sense=0x4, - ccw_sense_id=0xe4, - ccw_transfer_in_channel0=0x8, - ccw_transfer_in_channel1=0x8, - ccw_set_x_mode=0xc3, // according to uli's lan notes - ccw_nop=0x3 // according to uli's notes again - // n.b. ccw_control clashes with this - // so I presume its a special case of - // control -}; - - - -#endif - - - - - - - diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/major.h linux/include/asm-s390/major.h --- v2.4.3/linux/include/asm-s390/major.h Fri May 12 11:41:44 2000 +++ linux/include/asm-s390/major.h Wed Dec 31 16:00:00 1969 @@ -1,150 +0,0 @@ -#ifndef _LINUX_MAJOR_H -#define _LINUX_MAJOR_H - -/* - * This file has definitions for major device numbers. - * For the device number assignments, see Documentation/devices.txt. - */ - -/* limits */ - -/* - * Important: Don't change this to 256. Major number 255 is and must be - * reserved for future expansion into a larger dev_t space. - */ -#define MAX_CHRDEV 255 -#define MAX_BLKDEV 255 - -#define UNNAMED_MAJOR 0 -#define MEM_MAJOR 1 -#define RAMDISK_MAJOR 1 -#define FLOPPY_MAJOR 2 -#define PTY_MASTER_MAJOR 2 -#define IDE0_MAJOR 3 -#define PTY_SLAVE_MAJOR 3 -#define HD_MAJOR IDE0_MAJOR -#define TTY_MAJOR 4 -#define TTYAUX_MAJOR 5 -#define LP_MAJOR 6 -#define VCS_MAJOR 7 -#define LOOP_MAJOR 7 -#define SCSI_DISK0_MAJOR 8 -#define SCSI_TAPE_MAJOR 9 -#define MD_MAJOR 9 -#define MISC_MAJOR 10 -#define SCSI_CDROM_MAJOR 11 -#define QIC02_TAPE_MAJOR 12 -#define XT_DISK_MAJOR 13 -#define SOUND_MAJOR 14 -#define CDU31A_CDROM_MAJOR 15 -#define JOYSTICK_MAJOR 15 -#define GOLDSTAR_CDROM_MAJOR 16 -#define OPTICS_CDROM_MAJOR 17 -#define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 -#define MITSUMI_X_CDROM_MAJOR 20 -#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ -#define SCSI_GENERIC_MAJOR 21 -#define Z8530_MAJOR 34 -#define DIGI_MAJOR 23 -#define IDE1_MAJOR 22 -#define DIGICU_MAJOR 22 -#define MITSUMI_CDROM_MAJOR 23 -#define CDU535_CDROM_MAJOR 24 -#define STL_SERIALMAJOR 24 -#define MATSUSHITA_CDROM_MAJOR 25 -#define STL_CALLOUTMAJOR 25 -#define MATSUSHITA_CDROM2_MAJOR 26 -#define QIC117_TAPE_MAJOR 27 -#define MATSUSHITA_CDROM3_MAJOR 27 -#define MATSUSHITA_CDROM4_MAJOR 28 -#define STL_SIOMEMMAJOR 28 -#define ACSI_MAJOR 28 -#define AZTECH_CDROM_MAJOR 29 -#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ -#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ -#define CM206_CDROM_MAJOR 32 -#define IDE2_MAJOR 33 -#define IDE3_MAJOR 34 -#define NETLINK_MAJOR 36 -#define PS2ESDI_MAJOR 36 -#define IDETAPE_MAJOR 37 -#define Z2RAM_MAJOR 37 -#define APBLOCK_MAJOR 38 /* AP1000 Block device */ -#define DDV_MAJOR 39 /* AP1000 DDV block device */ -#define NBD_MAJOR 43 /* Network block device */ -#define RISCOM8_NORMAL_MAJOR 48 -#define DAC960_MAJOR 48 /* 48..55 */ -#define RISCOM8_CALLOUT_MAJOR 49 -#define MKISS_MAJOR 55 -#define DSP56K_MAJOR 55 /* DSP56001 processor device */ - -#define IDE4_MAJOR 56 -#define IDE5_MAJOR 57 - -#define SCSI_DISK1_MAJOR 65 -#define SCSI_DISK2_MAJOR 66 -#define SCSI_DISK3_MAJOR 67 -#define SCSI_DISK4_MAJOR 68 -#define SCSI_DISK5_MAJOR 69 -#define SCSI_DISK6_MAJOR 70 -#define SCSI_DISK7_MAJOR 71 - - -#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ - -#define COMPAQ_SMART2_MAJOR 72 -#define COMPAQ_SMART2_MAJOR1 73 -#define COMPAQ_SMART2_MAJOR2 74 -#define COMPAQ_SMART2_MAJOR3 75 -#define COMPAQ_SMART2_MAJOR4 76 -#define COMPAQ_SMART2_MAJOR5 77 -#define COMPAQ_SMART2_MAJOR6 78 -#define COMPAQ_SMART2_MAJOR7 79 - -#define SPECIALIX_NORMAL_MAJOR 75 -#define SPECIALIX_CALLOUT_MAJOR 76 - -#define DASD_MAJOR 94 - -#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ - -#define MDISK_MAJOR 64 - -#define I2O_MAJOR 80 /* 80->87 */ - -#define IDE6_MAJOR 88 -#define IDE7_MAJOR 89 -#define IDE8_MAJOR 90 -#define IDE9_MAJOR 91 - -#define AURORA_MAJOR 79 - -#define RTF_MAJOR 150 -#define RAW_MAJOR 162 - -#define USB_ACM_MAJOR 166 -#define USB_ACM_AUX_MAJOR 167 -#define USB_CHAR_MAJOR 180 - -#define UNIX98_PTY_MASTER_MAJOR 128 -#define UNIX98_PTY_MAJOR_COUNT 8 -#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) - -/* - * Tests for SCSI devices. - */ - -#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) - -#define SCSI_BLK_MAJOR(M) \ - (SCSI_DISK_MAJOR(M) \ - || (M) == SCSI_CDROM_MAJOR) - -static __inline__ int scsi_blk_major(int m) { - return SCSI_BLK_MAJOR(m); -} - -#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/mathemu.h linux/include/asm-s390/mathemu.h --- v2.4.3/linux/include/asm-s390/mathemu.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/mathemu.h Wed Apr 11 19:02:28 2001 @@ -22,28 +22,6 @@ extern int math_emu_stfpc(__u8 *, struct pt_regs *); extern int math_emu_srnm(__u8 *, struct pt_regs *); - -extern __u64 __adddf3(__u64,__u64); -extern __u64 __subdf3(__u64,__u64); -extern __u64 __muldf3(__u64,__u64); -extern __u64 __divdf3(__u64,__u64); -extern long __cmpdf2(__u64,__u64); -extern __u64 __negdf2(__u64); -extern __u64 __absdf2(__u64); -extern __u32 __addsf3(__u32,__u32); -extern __u32 __subsf3(__u32,__u32); -extern __u32 __mulsf3(__u32,__u32); -extern __u32 __divsf3(__u32,__u32); -extern __u32 __negsf2(__u32); -extern __u32 __abssf2(__u32); -extern long __cmpsf2(__u32,__u32); -extern __u32 __truncdfsf2(__u64); -extern __u32 __fixsfsi(__u32); -extern __u32 __fixdfsi(__u64); -extern __u64 __floatsidf(__u32); -extern __u32 __floatsisf(__u32); -extern __u64 __extendsfdf2(__u32); - #endif /* __MATHEMU__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/misc390.h linux/include/asm-s390/misc390.h --- v2.4.3/linux/include/asm-s390/misc390.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/misc390.h Wed Dec 31 16:00:00 1969 @@ -1,15 +0,0 @@ -/* - * include/asm-s390/misc390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#define allocaligned2(type,name,number,align) \ - __u8 name##buff[(sizeof(type)*(number+1))-1]; \ - type *name=(type *)(((__u32)(&name##buff[align-1]))&(-align)) - -#define allocaligned(type,name,number) allocaligned2(type,name,number,__alignof__(type)) - -extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs); diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/page.h linux/include/asm-s390/page.h --- v2.4.3/linux/include/asm-s390/page.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/page.h Wed Apr 11 19:02:28 2001 @@ -9,6 +9,9 @@ #ifndef _S390_PAGE_H #define _S390_PAGE_H +#include <asm/setup.h> +#include <asm/types.h> + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -17,12 +20,44 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -/* - * gcc uses builtin, i.e. MVCLE for both operations - */ +static inline void clear_page(void *page) +{ + register_pair rp; + + rp.subreg.even = (unsigned long) page; + rp.subreg.odd = (unsigned long) 4096; + asm volatile (" slr 1,1\n" + " mvcl %0,0" + : "+&a" (rp) : : "memory", "1" ); +} -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) -#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +static inline void copy_page(void *to, void *from) +{ + if (MACHINE_HAS_MVPG) + asm volatile (" sr 0,0\n" + " mvpg %0,%1" + : : "a" ((void *)(to)), "a" ((void *)(from)) + : "memory", "0" ); + else + asm volatile (" mvc 0(256,%0),0(%1)\n" + " mvc 256(256,%0),256(%1)\n" + " mvc 512(256,%0),512(%1)\n" + " mvc 768(256,%0),768(%1)\n" + " mvc 1024(256,%0),1024(%1)\n" + " mvc 1280(256,%0),1280(%1)\n" + " mvc 1536(256,%0),1536(%1)\n" + " mvc 1792(256,%0),1792(%1)\n" + " mvc 2048(256,%0),2048(%1)\n" + " mvc 2304(256,%0),2304(%1)\n" + " mvc 2560(256,%0),2560(%1)\n" + " mvc 2816(256,%0),2816(%1)\n" + " mvc 3072(256,%0),3072(%1)\n" + " mvc 3328(256,%0),3328(%1)\n" + " mvc 3584(256,%0),3584(%1)\n" + " mvc 3840(256,%0),3840(%1)\n" + : : "a"((void *)(to)),"a"((void *)(from)) + : "memory" ); +} #define clear_user_page(page, vaddr) clear_page(page) #define copy_user_page(to, from, vaddr) copy_page(to, from) diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/pgalloc.h linux/include/asm-s390/pgalloc.h --- v2.4.3/linux/include/asm-s390/pgalloc.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/pgalloc.h Wed Apr 11 19:02:28 2001 @@ -30,12 +30,14 @@ extern __inline__ pgd_t* get_pgd_slow(void) { + pgd_t *ret; int i; - pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1); - if (ret) - for (i=0,pgd=ret;i<USER_PTRS_PER_PGD;i++,pgd++) - pmd_clear(pmd_offset(pgd,i*PGDIR_SIZE)); - return ret; + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL,1); + if (ret != NULL) + for (i = 0; i < USER_PTRS_PER_PGD; i++) + pmd_clear(pmd_offset(ret + i, i*PGDIR_SIZE)); + return ret; } extern __inline__ pgd_t* get_pgd_fast(void) @@ -76,40 +78,40 @@ /* * page middle directory allocation/free routines. - * We don't use pmd cache, so these are dummy routines. + * We don't use pmd cache, so these are dummy routines. This + * code never triggers because the pgd will always be present. */ -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ -} - -extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ +#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() + +extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) +{ + pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); + pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256); + pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte+512); + pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768); } -extern inline void pmd_free(pmd_t * pmd) -{ -} - -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc - /* * page table entry allocation/free routines. */ -extern pte_t empty_bad_pte_table[]; -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) +{ + pte_t *pte; + int i; -extern __inline__ pte_t* get_pte_fast(void) + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte != NULL) { + for (i=0; i < PTRS_PER_PTE; i++) + pte_clear(pte+i); + } + return pte; +} + +extern __inline__ pte_t * +pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret = (unsigned long *) pte_quicklist; @@ -121,44 +123,19 @@ return (pte_t *)ret; } -extern __inline__ void free_pte_fast(pte_t *pte) +extern __inline__ void pte_free_fast(pte_t *pte) { - if (pte == empty_bad_pte_table) - return; *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern __inline__ void free_pte_slow(pte_t *pte) +extern __inline__ void pte_free_slow(pte_t *pte) { free_page((unsigned long) pte); } -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long vmaddr) -{ - unsigned long offset; - - offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - unsigned long page = (unsigned long) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, offset); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(page); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(page+1024); - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(page+2048); - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(page+3072); - return (pte_t *) page + offset; - } - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) +#define pte_free(pte) pte_free_fast(pte) extern int do_check_pgt_cache(int, int); @@ -200,11 +177,28 @@ * on each context switch */ -#define flush_tlb() local_flush_tlb() -#define flush_tlb_all() local_flush_tlb() -#define flush_tlb_mm(mm) local_flush_tlb() -#define flush_tlb_page(vma, va) local_flush_tlb() -#define flush_tlb_range(mm, start, end) local_flush_tlb() +static inline void flush_tlb(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_all(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + local_flush_tlb(); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + local_flush_tlb(); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + local_flush_tlb(); +} #else @@ -251,11 +245,28 @@ } } -#define flush_tlb() __flush_tlb_mm(current->mm) -#define flush_tlb_all() global_flush_tlb() -#define flush_tlb_mm(mm) __flush_tlb_mm(mm) -#define flush_tlb_page(vma, va) __flush_tlb_mm((vma)->vm_mm) -#define flush_tlb_range(mm, start, end) __flush_tlb_mm(mm) +static inline void flush_tlb(void) +{ + __flush_tlb_mm(current->mm); +} +static inline void flush_tlb_all(void) +{ + global_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + __flush_tlb_mm(mm); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + __flush_tlb_mm(vma->vm_mm); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + __flush_tlb_mm(mm); +} #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/ptrace.h linux/include/asm-s390/ptrace.h --- v2.4.3/linux/include/asm-s390/ptrace.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/ptrace.h Wed Apr 11 19:02:28 2001 @@ -8,63 +8,220 @@ #ifndef _S390_PTRACE_H #define _S390_PTRACE_H + +/* + * Offsets in the user_regs_struct. They are used for the ptrace + * system call and in entry.S + */ +#define PT_PSWMASK 0x00 +#define PT_PSWADDR 0x04 +#define PT_GPR0 0x08 +#define PT_GPR1 0x0C +#define PT_GPR2 0x10 +#define PT_GPR3 0x14 +#define PT_GPR4 0x18 +#define PT_GPR5 0x1C +#define PT_GPR6 0x20 +#define PT_GPR7 0x24 +#define PT_GPR8 0x28 +#define PT_GPR9 0x2C +#define PT_GPR10 0x30 +#define PT_GPR11 0x34 +#define PT_GPR12 0x38 +#define PT_GPR13 0x3C +#define PT_GPR14 0x40 +#define PT_GPR15 0x44 +#define PT_ACR0 0x48 +#define PT_ACR1 0x4C +#define PT_ACR2 0x50 +#define PT_ACR3 0x54 +#define PT_ACR4 0x58 +#define PT_ACR5 0x5C +#define PT_ACR6 0x60 +#define PT_ACR7 0x64 +#define PT_ACR8 0x68 +#define PT_ACR9 0x6C +#define PT_ACR10 0x70 +#define PT_ACR11 0x74 +#define PT_ACR12 0x78 +#define PT_ACR13 0x7C +#define PT_ACR14 0x80 +#define PT_ACR15 0x84 +#define PT_ORIGGPR2 0x88 +#define PT_FPC 0x90 +/* + * A nasty fact of life that the ptrace api + * only supports passing of longs. + */ +#define PT_FPR0_HI 0x98 +#define PT_FPR0_LO 0x9C +#define PT_FPR1_HI 0xA0 +#define PT_FPR1_LO 0xA4 +#define PT_FPR2_HI 0xA8 +#define PT_FPR2_LO 0xAC +#define PT_FPR3_HI 0xB0 +#define PT_FPR3_LO 0xB4 +#define PT_FPR4_HI 0xB8 +#define PT_FPR4_LO 0xBC +#define PT_FPR5_HI 0xC0 +#define PT_FPR5_LO 0xC4 +#define PT_FPR6_HI 0xC8 +#define PT_FPR6_LO 0xCC +#define PT_FPR7_HI 0xD0 +#define PT_FPR7_LO 0xD4 +#define PT_FPR8_HI 0xD8 +#define PT_FPR8_LO 0XDC +#define PT_FPR9_HI 0xE0 +#define PT_FPR9_LO 0xE4 +#define PT_FPR10_HI 0xE8 +#define PT_FPR10_LO 0xEC +#define PT_FPR11_HI 0xF0 +#define PT_FPR11_LO 0xF4 +#define PT_FPR12_HI 0xF8 +#define PT_FPR12_LO 0xFC +#define PT_FPR13_HI 0x100 +#define PT_FPR13_LO 0x104 +#define PT_FPR14_HI 0x108 +#define PT_FPR14_LO 0x10C +#define PT_FPR15_HI 0x110 +#define PT_FPR15_LO 0x114 +#define PT_CR_9 0x118 +#define PT_CR_10 0x11C +#define PT_CR_11 0x120 +#define PT_IEEE_IP 0x13C +#define PT_LASTOFF PT_IEEE_IP +#define PT_ENDREGS 0x140-1 + +#define NUM_GPRS 16 +#define NUM_FPRS 16 +#define NUM_CRS 16 +#define NUM_ACRS 16 +#define GPR_SIZE 4 +#define FPR_SIZE 8 +#define FPC_SIZE 4 +#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ +#define CR_SIZE 4 +#define ACR_SIZE 4 + +#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */ + +#ifndef __ASSEMBLY__ #include <linux/config.h> -#include <asm/s390-regs-common.h> -#include <asm/current.h> +#include <linux/stddef.h> #include <linux/types.h> + +#include <asm/current.h> #include <asm/setup.h> -#include <linux/stddef.h> +/* this typedef defines how a Program Status Word looks like */ +typedef struct +{ + __u32 mask; + __u32 addr; +} psw_t __attribute__ ((aligned(8))); + +#ifdef __KERNEL__ +#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL) +#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff) +#endif -#define S390_REGS \ -S390_REGS_COMMON \ -__u32 orig_gpr2; +typedef union +{ + float f; + double d; + __u64 ui; + struct + { + __u32 hi; + __u32 lo; + } fp; +} freg_t; + +typedef struct +{ + __u32 fpc; + freg_t fprs[NUM_FPRS]; +} s390_fp_regs; + +#define FPC_EXCEPTION_MASK 0xF8000000 +#define FPC_FLAGS_MASK 0x00F80000 +#define FPC_DXC_MASK 0x0000FF00 +#define FPC_RM_MASK 0x00000003 +#define FPC_VALID_MASK 0xF8F8FF03 +/* + * The first entries in pt_regs, gdb_pt_regs and user_regs_struct + * are common for all three structures. The s390_regs structure + * covers the common parts. It simplifies copying the common part + * between the three structures. + */ typedef struct { - S390_REGS + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; } s390_regs; +/* + * The pt_regs struct defines the way the registers are stored on + * the stack during a system call. + */ struct pt_regs { - S390_REGS + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; __u32 trap; + __u32 old_ilc; }; +/* + * The gdb_pt_regs struct is used instead of the pt_regs structure + * if kernel remote debugging is used. + */ #if CONFIG_REMOTE_DEBUG -typedef struct +struct gdb_pt_regs { - S390_REGS + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; __u32 trap; __u32 crs[16]; s390_fp_regs fp_regs; -} gdb_pt_regs; +}; #endif - +/* + * Now for the program event recording (trace) definitions. + */ typedef struct { - __u32 cr[3]; + __u32 cr[3]; } per_cr_words __attribute__((packed)); #define PER_EM_MASK 0xE8000000 + typedef struct { - unsigned em_branching:1; - unsigned em_instruction_fetch:1; - /* Switching on storage alteration automatically fixes - the storage alteration event bit in the users std. */ - unsigned em_storage_alteration:1; - unsigned em_gpr_alt_unused:1; - unsigned em_store_real_address:1; - unsigned :3; - unsigned branch_addr_ctl:1; - unsigned :1; - unsigned storage_alt_space_ctl:1; - unsigned :5; - unsigned :16; - addr_t starting_addr; - addr_t ending_addr; + unsigned em_branching : 1; + unsigned em_instruction_fetch : 1; + /* + * Switching on storage alteration automatically fixes + * the storage alteration event bit in the users std. + */ + unsigned em_storage_alteration : 1; + unsigned em_gpr_alt_unused : 1; + unsigned em_store_real_address : 1; + unsigned : 3; + unsigned branch_addr_ctl : 1; + unsigned : 1; + unsigned storage_alt_space_ctl : 1; + unsigned : 21; + addr_t starting_addr; + addr_t ending_addr; } per_cr_bits __attribute__((packed)); typedef struct @@ -76,228 +233,59 @@ typedef struct { - unsigned perc_branching:1; /* 0x096 */ - unsigned perc_instruction_fetch:1; - unsigned perc_storage_alteration:1; - unsigned perc_gpr_alt_unused:1; - unsigned perc_store_real_address:1; - unsigned :3; - unsigned :1; - unsigned atmid_validity_bit:1; - unsigned atmid_psw_bit_32:1; - unsigned atmid_psw_bit_5:1; - unsigned atmid_psw_bit_16:1; - unsigned atmid_psw_bit_17:1; - unsigned si:2; - addr_t address; /* 0x098 */ - unsigned :4; /* 0x0a1 */ - unsigned access_id:4; + unsigned perc_branching : 1; /* 0x096 */ + unsigned perc_instruction_fetch : 1; + unsigned perc_storage_alteration : 1; + unsigned perc_gpr_alt_unused : 1; + unsigned perc_store_real_address : 1; + unsigned : 4; + unsigned atmid_validity_bit : 1; + unsigned atmid_psw_bit_32 : 1; + unsigned atmid_psw_bit_5 : 1; + unsigned atmid_psw_bit_16 : 1; + unsigned atmid_psw_bit_17 : 1; + unsigned si : 2; + addr_t address; /* 0x098 */ + unsigned : 4; /* 0x0a1 */ + unsigned access_id : 4; } per_lowcore_bits __attribute__((packed)); -typedef enum -{ - primary_asce, - ar_asce, - secondary_asce, - home_space_asce -} per_ai_codes; - typedef struct { - union - { + union { per_cr_words words; per_cr_bits bits; } control_regs __attribute__((packed)); - /* Use these flags instead of setting em_instruction_fetch */ - /* directly they are used so that single stepping can be */ - /* switched on & off while not affecting other tracing */ - unsigned single_step:1; - unsigned instruction_fetch:1; - unsigned :30; - /* These addresses are copied into cr10 & cr11 if single stepping - is switched off */ + /* + * Use these flags instead of setting em_instruction_fetch + * directly they are used so that single stepping can be + * switched on & off while not affecting other tracing + */ + unsigned single_step : 1; + unsigned instruction_fetch : 1; + unsigned : 30; + /* + * These addresses are copied into cr10 & cr11 if single + * stepping is switched off + */ __u32 starting_addr; __u32 ending_addr; - union - { + union { per_lowcore_words words; per_lowcore_bits bits; } lowcore; } per_struct __attribute__((packed)); - - -/* this struct defines the way the registers are stored on the - stack during a system call. If you change the pt_regs structure, - you'll need to change user.h too. - - N.B. if you modify the pt_regs struct the strace command also has to be - modified & recompiled ( just wait till we have gdb going ). - -*/ - -struct user_regs_struct -{ - S390_REGS - s390_fp_regs fp_regs; -/* These per registers are in here so that gdb can modify them itself - * as there is no "official" ptrace interface for hardware watchpoints. - * this is the way intel does it - */ - per_struct per_info; - addr_t ieee_instruction_pointer; - /* Used to give failing instruction back to user for ieee exceptions */ -}; - -typedef struct user_regs_struct user_regs_struct; - -typedef struct pt_regs pt_regs; - -#ifdef __KERNEL__ -#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) -#define instruction_pointer(regs) ((regs)->psw.addr) -extern void show_regs(struct pt_regs * regs); -extern char *task_show_regs(struct task_struct *task, char *buffer); -#endif - - - - - -#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL) - -#define MULT_PROCPTR_TYPES ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC)) - -typedef struct -{ - long addr; - long toc; -} routine_descriptor; -extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs); -extern __inline__ void -fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs) -{ - regs->psw.addr=FIX_PSW(rdes->addr); - regs->gprs[12]=rdes->toc; -} - -/* - * Compiler optimisation should save this stuff from being non optimal - * & remove uneccessary code ( isnt gcc great DJB. ) - */ - -/*I'm just using this an indicator of what binformat we are using - * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise - * dereferencing incomplete pointer types in with load_toc_binary - */ -#if MULT_PROCPTR_TYPES -#define uses_routine_descriptors() \ -(current->binfmt->load_binary==load_toc_binary) -#else -#if CONFIG_BINFMT_TOC -#define uses_routine_descriptors() 1 -#else -#define uses_routine_descriptors() 0 -#endif -#endif - -#define pt_off(ptreg) offsetof(user_regs_struct,ptreg) -enum -{ - PT_PSWMASK=pt_off(psw.mask), - PT_PSWADDR=pt_off(psw.addr), - PT_GPR0=pt_off(gprs[0]), - PT_GPR1=pt_off(gprs[1]), - PT_GPR2=pt_off(gprs[2]), - PT_GPR3=pt_off(gprs[3]), - PT_GPR4=pt_off(gprs[4]), - PT_GPR5=pt_off(gprs[5]), - PT_GPR6=pt_off(gprs[6]), - PT_GPR7=pt_off(gprs[7]), - PT_GPR8=pt_off(gprs[8]), - PT_GPR9=pt_off(gprs[9]), - PT_GPR10=pt_off(gprs[10]), - PT_GPR11=pt_off(gprs[11]), - PT_GPR12=pt_off(gprs[12]), - PT_GPR13=pt_off(gprs[13]), - PT_GPR14=pt_off(gprs[14]), - PT_GPR15=pt_off(gprs[15]), - PT_ACR0=pt_off(acrs[0]), - PT_ACR1=pt_off(acrs[1]), - PT_ACR2=pt_off(acrs[2]), - PT_ACR3=pt_off(acrs[3]), - PT_ACR4=pt_off(acrs[4]), - PT_ACR5=pt_off(acrs[5]), - PT_ACR6=pt_off(acrs[6]), - PT_ACR7=pt_off(acrs[7]), - PT_ACR8=pt_off(acrs[8]), - PT_ACR9=pt_off(acrs[9]), - PT_ACR10=pt_off(acrs[10]), - PT_ACR11=pt_off(acrs[11]), - PT_ACR12=pt_off(acrs[12]), - PT_ACR13=pt_off(acrs[13]), - PT_ACR14=pt_off(acrs[14]), - PT_ACR15=pt_off(acrs[15]), - PT_ORIGGPR2=pt_off(orig_gpr2), - PT_FPC=pt_off(fp_regs.fpc), -/* - * A nasty fact of life that the ptrace api - * only supports passing of longs. - */ - PT_FPR0_HI=pt_off(fp_regs.fprs[0].fp.hi), - PT_FPR0_LO=pt_off(fp_regs.fprs[0].fp.lo), - PT_FPR1_HI=pt_off(fp_regs.fprs[1].fp.hi), - PT_FPR1_LO=pt_off(fp_regs.fprs[1].fp.lo), - PT_FPR2_HI=pt_off(fp_regs.fprs[2].fp.hi), - PT_FPR2_LO=pt_off(fp_regs.fprs[2].fp.lo), - PT_FPR3_HI=pt_off(fp_regs.fprs[3].fp.hi), - PT_FPR3_LO=pt_off(fp_regs.fprs[3].fp.lo), - PT_FPR4_HI=pt_off(fp_regs.fprs[4].fp.hi), - PT_FPR4_LO=pt_off(fp_regs.fprs[4].fp.lo), - PT_FPR5_HI=pt_off(fp_regs.fprs[5].fp.hi), - PT_FPR5_LO=pt_off(fp_regs.fprs[5].fp.lo), - PT_FPR6_HI=pt_off(fp_regs.fprs[6].fp.hi), - PT_FPR6_LO=pt_off(fp_regs.fprs[6].fp.lo), - PT_FPR7_HI=pt_off(fp_regs.fprs[7].fp.hi), - PT_FPR7_LO=pt_off(fp_regs.fprs[7].fp.lo), - PT_FPR8_HI=pt_off(fp_regs.fprs[8].fp.hi), - PT_FPR8_LO=pt_off(fp_regs.fprs[8].fp.lo), - PT_FPR9_HI=pt_off(fp_regs.fprs[9].fp.hi), - PT_FPR9_LO=pt_off(fp_regs.fprs[9].fp.lo), - PT_FPR10_HI=pt_off(fp_regs.fprs[10].fp.hi), - PT_FPR10_LO=pt_off(fp_regs.fprs[10].fp.lo), - PT_FPR11_HI=pt_off(fp_regs.fprs[11].fp.hi), - PT_FPR11_LO=pt_off(fp_regs.fprs[11].fp.lo), - PT_FPR12_HI=pt_off(fp_regs.fprs[12].fp.hi), - PT_FPR12_LO=pt_off(fp_regs.fprs[12].fp.lo), - PT_FPR13_HI=pt_off(fp_regs.fprs[13].fp.hi), - PT_FPR13_LO=pt_off(fp_regs.fprs[13].fp.lo), - PT_FPR14_HI=pt_off(fp_regs.fprs[14].fp.hi), - PT_FPR14_LO=pt_off(fp_regs.fprs[14].fp.lo), - PT_FPR15_HI=pt_off(fp_regs.fprs[15].fp.hi), - PT_FPR15_LO=pt_off(fp_regs.fprs[15].fp.lo), - PT_CR_9=pt_off(per_info.control_regs.words.cr[0]), - PT_CR_10=pt_off(per_info.control_regs.words.cr[1]), - PT_CR_11=pt_off(per_info.control_regs.words.cr[2]), - PT_IEEE_IP=pt_off(ieee_instruction_pointer), - PT_LASTOFF=PT_IEEE_IP, - PT_ENDREGS=sizeof(user_regs_struct)-1 -}; - -#define PTRACE_AREA \ -__u32 len; \ -addr_t kernel_addr; \ -addr_t process_addr; - typedef struct { - PTRACE_AREA + __u32 len; + addr_t kernel_addr; + addr_t process_addr; } ptrace_area; /* - 390 specific non posix ptrace requests - I chose unusual values so they are unlikely to clash with future ptrace definitions. + * S/390 specific non posix ptrace requests. I chose unusual values so + * they are unlikely to clash with future ptrace definitions. */ #define PTRACE_PEEKUSR_AREA 0x5000 #define PTRACE_POKEUSR_AREA 0x5001 @@ -305,7 +293,10 @@ #define PTRACE_PEEKDATA_AREA 0x5003 #define PTRACE_POKETEXT_AREA 0x5004 #define PTRACE_POKEDATA_AREA 0x5005 -/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */ +/* + * PT_PROT definition is loosely based on hppa bsd definition in + * gdb/hppab-nat.c + */ #define PTRACE_PROT 21 typedef enum @@ -321,18 +312,41 @@ addr_t hiaddr; ptprot_flags prot; } ptprot_area; -#endif - - - - - - - - - +/* Sequence of bytes for breakpoint illegal instruction. */ +#define S390_BREAKPOINT {0x0,0x1} +#define S390_BREAKPOINT_U16 ((__u16)0x0001) +#define S390_SYSCALL_OPCODE ((__u16)0x0a00) +#define S390_SYSCALL_SIZE 2 +/* + * The user_regs_struct defines the way the user registers are + * store on the stack for signal handling. + */ +struct user_regs_struct +{ + psw_t psw; + __u32 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u32 orig_gpr2; + s390_fp_regs fp_regs; + /* + * These per registers are in here so that gdb can modify them + * itself as there is no "official" ptrace interface for hardware + * watchpoints. This is the way intel does it. + */ + per_struct per_info; + addr_t ieee_instruction_pointer; + /* Used to give failing instruction back to user for ieee exceptions */ +}; +#ifdef __KERNEL__ +#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) +#define instruction_pointer(regs) ((regs)->psw.addr) +extern void show_regs(struct pt_regs * regs); +extern char *task_show_regs(struct task_struct *task, char *buffer); +#endif +#endif /* __ASSEMBLY__ */ +#endif /* _S390_PTRACE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/queue.h linux/include/asm-s390/queue.h --- v2.4.3/linux/include/asm-s390/queue.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/queue.h Wed Apr 11 19:02:28 2001 @@ -7,8 +7,8 @@ * * A little set of queue utilies. */ + #include <linux/stddef.h> -#include <asm/types.h> typedef struct queue { @@ -105,8 +105,8 @@ for(curr=lhead;curr!=NULL;curr=curr->next) if(curr==member) - return(TRUE); - return(FALSE); + return(1); + return(0); } static __inline__ int get_prev(list *lhead,list *member,list **prev) @@ -117,11 +117,11 @@ for(curr=lhead;curr!=NULL;curr=curr->next) { if(curr==member) - return(TRUE); + return(1); *prev=curr; } *prev=NULL; - return(FALSE); + return(0); } @@ -137,9 +137,9 @@ prev->next=member->next; else *lhead=member->next; - return(TRUE); + return(1); } - return(FALSE); + return(0); } static __inline__ int remove_from_queue(qheader *qhead,queue *member) @@ -161,9 +161,9 @@ qhead->tail=NULL; qhead->head=member->next; } - return(TRUE); + return(1); } - return(FALSE); + return(0); } diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/s390-regs-common.h linux/include/asm-s390/s390-regs-common.h --- v2.4.3/linux/include/asm-s390/s390-regs-common.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/s390-regs-common.h Wed Dec 31 16:00:00 1969 @@ -1,112 +0,0 @@ -/* - * include/asm-s390/s390-regs-common.h - * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * - * this file is designed to keep as much compatibility between - * gdb's representation of registers & the kernels representation of registers - * as possible so as to minimise translation between gdb registers & - * kernel registers please keep this matched with gdb & strace - */ - -#ifndef _S390_REGS_COMMON_H -#define _S390_REGS_COMMON_H -#ifndef __ASSEMBLY__ -#include <asm/types.h> -#endif -#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) -#define REGISTER_SIZE 4 -#endif -#define NUM_GPRS 16 -#define GPR_SIZE 4 -#define PSW_MASK_SIZE 4 -#define PSW_ADDR_SIZE 4 -#define NUM_FPRS 16 -#define FPR_SIZE 8 -#define FPC_SIZE 4 -#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ -#define NUM_CRS 16 -#define CR_SIZE 4 -#define NUM_ACRS 16 -#define ACR_SIZE 4 - -#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */ - -#ifndef __ASSEMBLY__ -/* this typedef defines how a Program Status Word looks like */ -typedef struct -{ - __u32 mask; - __u32 addr; -} psw_t __attribute__ ((aligned(8))); - -/* 2 __u32's are used for floats instead to compile with a __STRICT_ANSI__ defined */ -typedef union -{ -#ifdef __KERNEL__ - __u64 d; /* mathemu.h gets upset otherwise */ -#else - double d; /* ansi c dosen't like long longs & make sure that */ - /* alignments are identical for both compiles */ -#endif - struct - { - __u32 hi; - __u32 lo; - } fp; - __u32 f; -} freg_t; - -typedef struct -{ -/* - The compiler appears to like aligning freg_t on an 8 byte boundary - so I always access fpregs, this was causing fun when I was doing - coersions. - */ - __u32 fpc; - freg_t fprs[NUM_FPRS]; -} s390_fp_regs; - -#define FPC_EXCEPTION_MASK 0xF8000000 -#define FPC_FLAGS_MASK 0x00F80000 -#define FPC_DXC_MASK 0x0000FF00 -#define FPC_RM_MASK 0x00000003 -#define FPC_VALID_MASK ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \ - FPC_DXC_MASK|FPC_RM_MASK)) - -/* - gdb structures & the kernel have this much always in common - */ -#define S390_REGS_COMMON \ -psw_t psw; \ -__u32 gprs[NUM_GPRS]; \ -__u32 acrs[NUM_ACRS]; \ - -typedef struct -{ - S390_REGS_COMMON -} s390_regs_common; - - -/* Sequence of bytes for breakpoint illegal instruction. */ -#define S390_BREAKPOINT {0x0,0x1} -#define S390_BREAKPOINT_U16 ((__u16)0x0001) -#define S390_SYSCALL_OPCODE ((__u16)0x0a00) -#define S390_SYSCALL_SIZE 2 -#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) -#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff) -#endif -#endif -#endif - - - - - - - - - diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/s390dyn.h linux/include/asm-s390/s390dyn.h --- v2.4.3/linux/include/asm-s390/s390dyn.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/s390dyn.h Wed Apr 11 19:02:28 2001 @@ -10,6 +10,10 @@ #ifndef __s390dyn_h #define __s390dyn_h +#ifndef _LINUX_LIST_H +#include <linux/list.h> +#endif + struct _devreg; typedef int (* oper_handler_func_t)( int irq, @@ -23,6 +27,7 @@ } __attribute__ ((packed)) devreg_hc_t; typedef struct _devreg { + struct list_head list; union { int devno; devreg_hc_t hc; /* has controller info */ @@ -30,8 +35,6 @@ int flag; oper_handler_func_t oper_func; - struct _devreg *prev; - struct _devreg *next; } devreg_t; #define DEVREG_EXACT_MATCH 0x00000001 diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/s390io.h linux/include/asm-s390/s390io.h --- v2.4.3/linux/include/asm-s390/s390io.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/s390io.h Wed Apr 11 19:02:28 2001 @@ -75,7 +75,6 @@ unsigned long qintparm; /* queued interruption parameter */ unsigned long qflag; /* queued flags */ __u8 qlpm; /* queued logical path mask */ - __u32 syncnt; /* sync I/O recursive usage count */ } __attribute__ ((aligned(8))) ioinfo_t; diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/semaphore-helper.h linux/include/asm-s390/semaphore-helper.h --- v2.4.3/linux/include/asm-s390/semaphore-helper.h Fri May 12 11:41:44 2000 +++ linux/include/asm-s390/semaphore-helper.h Wed Dec 31 16:00:00 1969 @@ -1,100 +0,0 @@ -/* - * include/asm-s390/semaphore-helper.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * - * Derived from "include/asm-i386/semaphore-helper.h" - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -#ifndef _S390_SEMAPHORE_HELPER_H -#define _S390_SEMAPHORE_HELPER_H - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * but on the x86 we need an external synchronizer. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * If we give up we must undo our count-decrease we previously did in down(). - * Subtle: up() can continue to happens and increase the semaphore count - * even during our critical section protected by the spinlock. So - * we must remeber to undo the sem->waking that will be run from - * wake_one_more() some time soon, if the semaphore count become > 0. - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * Implementation details are the same of the interruptible case. - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - } else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/semaphore.h linux/include/asm-s390/semaphore.h --- v2.4.3/linux/include/asm-s390/semaphore.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/semaphore.h Tue Apr 17 17:19:31 2001 @@ -14,6 +14,7 @@ #include <asm/system.h> #include <asm/atomic.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -89,103 +90,6 @@ { if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subl'ing - * BIAS once per CPU will result in the long remaining - * negative. - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned int write_bias_granted; - volatile unsigned int read_bias_granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -}; - -#define RW_LOCK_BIAS 0x01000000 - -#define __RWSEM_DEBUG_INIT /* */ - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -} - -extern void __down_read_failed(int, struct rw_semaphore *); -extern void __down_write_failed(int, struct rw_semaphore *); -extern void __rwsem_wake(int, struct rw_semaphore *); - -static inline void down_read(struct rw_semaphore *sem) -{ - int count; - count = atomic_dec_return(&sem->count); - if (count < 0) - __down_read_failed(count, sem); -} - -static inline void down_write(struct rw_semaphore *sem) -{ - int count; - count = atomic_add_return (-RW_LOCK_BIAS, &sem->count); - if (count < 0) - __down_write_failed(count, sem); -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -static inline void up_read(struct rw_semaphore *sem) -{ - int count; - count = atomic_inc_return(&sem->count); - if (count == 0) - __rwsem_wake(count, sem); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -static inline void up_write(struct rw_semaphore *sem) -{ - int count; - count = atomic_add_return(RW_LOCK_BIAS, &sem->count); - if (count >= 0 && count < RW_LOCK_BIAS) - __rwsem_wake(count, sem); } #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/setup.h linux/include/asm-s390/setup.h --- v2.4.3/linux/include/asm-s390/setup.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/setup.h Wed Apr 11 19:02:28 2001 @@ -8,46 +8,36 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define PARMAREA 0x10400 +#define PARMAREA 0x10400 +#define COMMAND_LINE_SIZE 896 +#define RAMDISK_ORIGIN 0x800000 +#define RAMDISK_SIZE 0x800000 #ifndef __ASSEMBLER__ -#define ORIG_ROOT_DEV (*(unsigned long *) (0x10400)) -#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10404)) -#define MEMORY_SIZE (*(unsigned long *) (0x10406)) -#define MACHINE_FLAGS (*(unsigned long *) (0x1040a)) -#define INITRD_START (*(unsigned long *) (0x1040e)) -#define INITRD_SIZE (*(unsigned long *) (0x10412)) -#define RAMDISK_FLAGS (*(unsigned short *) (0x10416)) +#define IPL_DEVICE (*(unsigned long *) (0x10404)) +#define INITRD_START (*(unsigned long *) (0x1040C)) +#define INITRD_SIZE (*(unsigned long *) (0x10414)) #define COMMAND_LINE ((char *) (0x10480)) +/* + * Machine features detected in head.S + */ +extern unsigned long machine_flags; + +#define MACHINE_IS_VM (machine_flags & 1) +#define MACHINE_HAS_IEEE (machine_flags & 2) +#define MACHINE_IS_P390 (machine_flags & 4) +#define MACHINE_HAS_CSP (machine_flags & 8) +#define MACHINE_HAS_MVPG (machine_flags & 16) + #else -#define ORIG_ROOT_DEV 0x10400 -#define MOUNT_ROOT_RDONLY 0x10404 -#define MEMORY_SIZE 0x10406 -#define MACHINE_FLAGS 0x1040a -#define INITRD_START 0x1040e -#define INITRD_SIZE 0x10412 -#define RAMDISK_FLAGS 0x10416 +#define IPL_DEVICE 0x10404 +#define INITRD_START 0x1040C +#define INITRD_SIZE 0x10414 #define COMMAND_LINE 0x10480 #endif - -#define COMMAND_LINE_SIZE 896 -/* - * Machine features detected in head.S - */ -#define MACHINE_IS_VM (MACHINE_FLAGS & 1) -#define MACHINE_HAS_IEEE (MACHINE_FLAGS & 2) -#define MACHINE_IS_P390 (MACHINE_FLAGS & 4) -#define MACHINE_HAS_CSP (MACHINE_FLAGS & 8) - -#define RAMDISK_ORIGIN 0x800000 -#define RAMDISK_BLKSIZE 0x1000 -#define RAMDISK_IMAGE_START_MASK 0x07FF -#define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 - #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/sfp-machine.h linux/include/asm-s390/sfp-machine.h --- v2.4.3/linux/include/asm-s390/sfp-machine.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-s390/sfp-machine.h Thu Apr 12 12:16:36 2001 @@ -0,0 +1,139 @@ +/* Machine-dependent software floating-point definitions. + S/390 kernel version. + Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson (rth@cygnus.com), + Jakub Jelinek (jj@ultra.linux.cz), + David S. Miller (davem@redhat.com) and + Peter Maydell (pmaydell@chiark.greenend.org.uk). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SFP_MACHINE_H +#define _SFP_MACHINE_H + +#include <linux/config.h> + +#define _FP_W_TYPE_SIZE 32 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define _FP_MUL_MEAT_S(R,X,Y) \ + _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_D(R,X,Y) \ + _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_Q(R,X,Y) \ + _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) +#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) + +#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) +#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 +#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 +#define _FP_NANSIGN_S 0 +#define _FP_NANSIGN_D 0 +#define _FP_NANSIGN_Q 0 + +#define _FP_KEEPNANFRACP 1 + +/* + * If one NaN is signaling and the other is not, + * we choose that one, otherwise we choose X. + */ +#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ + do { \ + if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ + && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \ + { \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R,Y); \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + R##_c = FP_CLS_NAN; \ + } while (0) + +/* Some assembly to speed things up. */ +#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) ({ \ + unsigned int __r2 = (x2) + (y2); \ + unsigned int __r1 = (x1); \ + unsigned int __r0 = (x0); \ + __asm__ (" alr %2,%3\n" \ + " brc 12,0f\n" \ + " lhi 0,1\n" \ + " alr %1,0\n" \ + " brc 12,0f\n" \ + " alr %0,0\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \ + : "d" (y0), "i" (1) : "cc", "0" ); \ + __asm__ (" alr %1,%2\n" \ + " brc 12,0f\n" \ + " ahi %0,1\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1) \ + : "d" (y1) : "cc" ); \ + (r2) = __r2; \ + (r1) = __r1; \ + (r0) = __r0; \ +}) + +#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) ({ \ + unsigned int __r2 = (x2) - (y2); \ + unsigned int __r1 = (x1); \ + unsigned int __r0 = (x0); \ + __asm__ (" slr %2,%3\n" \ + " brc 3,0f\n" \ + " lhi 0,1\n" \ + " slr %1,0\n" \ + " brc 3,0f\n" \ + " slr %0,0\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \ + : "d" (y0) : "cc", "0" ); \ + __asm__ (" slr %1,%2\n" \ + " brc 3,0f\n" \ + " ahi %0,-1\n" \ + "0:" \ + : "+&d" (__r2), "+&d" (__r1) \ + : "d" (y1) : "cc" ); \ + (r2) = __r2; \ + (r1) = __r1; \ + (r0) = __r0; \ +}) + +#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE mode + +/* Exception flags. */ +#define FP_EX_INVALID 0x800000 +#define FP_EX_DIVZERO 0x400000 +#define FP_EX_OVERFLOW 0x200000 +#define FP_EX_UNDERFLOW 0x100000 +#define FP_EX_INEXACT 0x080000 + +/* We write the results always */ +#define FP_INHIBIT_RESULTS 0 + +#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/signal.h linux/include/asm-s390/signal.h --- v2.4.3/linux/include/asm-s390/signal.h Fri May 12 11:41:44 2000 +++ linux/include/asm-s390/signal.h Wed Apr 11 19:02:28 2001 @@ -71,6 +71,7 @@ #define SIGLOST 29 */ #define SIGPWR 30 +#define SIGSYS 31 #define SIGUNUSED 31 /* These should not be considered constants from userland. */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/sigp.h linux/include/asm-s390/sigp.h --- v2.4.3/linux/include/asm-s390/sigp.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/sigp.h Wed Apr 11 19:02:28 2001 @@ -15,7 +15,6 @@ #define __SIGP__ #include <asm/ptrace.h> -#include <asm/misc390.h> #include <asm/atomic.h> /* get real cpu address from logical cpu number */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/smp.h linux/include/asm-s390/smp.h --- v2.4.3/linux/include/asm-s390/smp.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/smp.h Wed Apr 11 19:02:28 2001 @@ -8,15 +8,24 @@ */ #ifndef __ASM_SMP_H #define __ASM_SMP_H + #include <linux/config.h> -#ifdef CONFIG_SMP -#ifndef __ASSEMBLY__ + +#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__) #include <asm/lowcore.h> -#include <linux/threads.h> // FOR NR_CPUS definition only. -#include <linux/kernel.h> // FOR FASTCALL definition -#define smp_processor_id() (current->processor) +/* + s390 specific smp.c headers + */ +typedef struct +{ + int intresting; + sigp_ccode ccode; + __u32 status; + __u16 cpu; +} sigp_info; + #define NO_PROC_ID 0xFF /* No processor magic marker */ /* @@ -31,7 +40,7 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -extern void count_cpus(void); +#define smp_processor_id() (current->processor) extern __inline__ int cpu_logical_map(int cpu) { @@ -55,25 +64,12 @@ void smp_local_timer_interrupt(struct pt_regs * regs); -/* - s390 specific smp.c headers - */ -typedef struct -{ - int intresting; - sigp_ccode ccode; - __u32 status; - __u16 cpu; -} sigp_info; - -sigp_ccode -smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait); -void smp_ext_call_others(void (*callback)(void *info), void *info, int wait); +sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait); +void smp_ext_call_others(void (*cb)(void *info), void *info, int wait); sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig); void smp_ext_bitcall_others(ec_bit_sig sig); int smp_signal_others(sigp_order_code order_code,__u32 parameter, int spin,sigp_info *info); -#endif #endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/spinlock.h linux/include/asm-s390/spinlock.h --- v2.4.3/linux/include/asm-s390/spinlock.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/spinlock.h Wed Apr 11 19:02:28 2001 @@ -73,6 +73,8 @@ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) + #define read_lock(rw) \ asm volatile(" l 2,%0\n" \ " j 1f\n" \ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/system.h linux/include/asm-s390/system.h --- v2.4.3/linux/include/asm-s390/system.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/system.h Wed Apr 11 19:02:28 2001 @@ -12,7 +12,6 @@ #define __ASM_SYSTEM_H #include <linux/config.h> -#include <asm/types.h> #ifdef __KERNEL__ #include <asm/lowcore.h> #endif @@ -33,6 +32,8 @@ #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +extern void __misaligned_u16(void); +extern void __misaligned_u32(void); static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { @@ -43,14 +44,14 @@ " nr 1,%0\n" /* isolate last 2 bits */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,8,%1\n" /* for ptr&3 == 0 */ - " stcm 0,8,%1\n" - " icm 1,4,%1\n" /* for ptr&3 == 1 */ - " stcm 0,4,%1\n" - " icm 1,2,%1\n" /* for ptr&3 == 2 */ - " stcm 0,2,%1\n" - " icm 1,1,%1\n" /* for ptr&3 == 3 */ - " stcm 0,1,%1\n" + " icm 1,8,3(%1)\n" /* for ptr&3 == 0 */ + " stcm 0,8,3(%1)\n" + " icm 1,4,3(%1)\n" /* for ptr&3 == 1 */ + " stcm 0,4,3(%1)\n" + " icm 1,2,3(%1)\n" /* for ptr&3 == 2 */ + " stcm 0,2,3(%1)\n" + " icm 1,1,3(%1)\n" /* for ptr&3 == 3 */ + " stcm 0,1,3(%1)\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -59,20 +60,21 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); + break; case 2: if(((__u32)ptr)&1) - panic("misaligned (__u16 *) in __xchg\n"); + __misaligned_u16(); asm volatile ( " lhi 1,2\n" " nr 1,%0\n" /* isolate bit 2^1 */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,12,%1\n" /* for ptr&2 == 0 */ - " stcm 0,12,%1\n" - " icm 1,3,%1\n" /* for ptr&2 == 1 */ - " stcm 0,3,%1\n" + " icm 1,12,2(%1)\n" /* for ptr&2 == 0 */ + " stcm 0,12,2(%1)\n" + " icm 1,3,2(%1)\n" /* for ptr&2 == 1 */ + " stcm 0,3,2(%1)\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -81,12 +83,12 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); break; case 4: if(((__u32)ptr)&3) - panic("misaligned (__u32 *) in __xchg\n"); + __misaligned_u32(); asm volatile ( " l 0,0(%1)\n" "0: cs 0,%0,0(%1)\n" diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/todclk.h linux/include/asm-s390/todclk.h --- v2.4.3/linux/include/asm-s390/todclk.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/todclk.h Wed Apr 11 19:02:28 2001 @@ -10,10 +10,14 @@ #ifndef __ASM_TODCLK_H #define __ASM_TODCLK_H +#ifdef __KERNEL__ + #define TOD_uSEC (0x1000ULL) #define TOD_mSEC (1000 * TOD_uSEC) #define TOD_SEC (1000 * TOD_mSEC) #define TOD_MIN (60 * TOD_SEC) #define TOD_HOUR (60 * TOD_MIN) + +#endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/types.h linux/include/asm-s390/types.h --- v2.4.3/linux/include/asm-s390/types.h Fri May 12 11:41:44 2000 +++ linux/include/asm-s390/types.h Wed Apr 11 19:02:28 2001 @@ -55,12 +55,13 @@ typedef u32 dma_addr_t; -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif +typedef union { + unsigned long long pair; + struct { + unsigned long even; + unsigned long odd; + } subreg; +} register_pair; #endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h --- v2.4.3/linux/include/asm-s390/uaccess.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/uaccess.h Wed Apr 11 19:02:28 2001 @@ -15,9 +15,7 @@ * User space memory access functions */ #include <linux/sched.h> -#if 0 -#include <asm/segment.h> -#endif + #define VERIFY_READ 0 #define VERIFY_WRITE 1 diff -u --recursive --new-file v2.4.3/linux/include/asm-s390/vtoc.h linux/include/asm-s390/vtoc.h --- v2.4.3/linux/include/asm-s390/vtoc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-s390/vtoc.h Wed Apr 11 19:02:28 2001 @@ -0,0 +1,234 @@ +#ifndef __KERNEL__ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> + +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/hdreg.h> +#include <linux/version.h> +#endif +#include <asm/dasd.h> + +#define LINE_LENGTH 80 +#define VTOC_START_CC 0x0 +#define VTOC_START_HH 0x1 + +enum failure {unable_to_open, + unable_to_seek, + unable_to_write, + unable_to_read}; + +typedef struct ttr { + __u16 tt; + __u8 r; +} __attribute__ ((packed)) ttr_t; + +typedef struct cchhb { + __u16 cc; + __u16 hh; + __u8 b; +} __attribute__ ((packed)) cchhb_t; + +typedef struct cchh { + __u16 cc; + __u16 hh; +} __attribute__ ((packed)) cchh_t; + +typedef struct labeldate { + __u8 year; + __u16 day; +} __attribute__ ((packed)) labeldate_t; + + +typedef struct volume_label { + char volkey[4]; /* volume key = volume label */ + char vollbl[4]; /* volume label */ + char volid[6]; /* volume identifier */ + __u8 security; /* security byte */ + cchhb_t vtoc; /* VTOC address */ + char res1[5]; /* reserved */ + char cisize[4]; /* CI-size for FBA,... */ + /* ...blanks for CKD */ + char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */ + char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */ + char res2[4]; /* reserved */ + char lvtoc[14]; /* owner code for LVTOC */ + char res3[29]; /* reserved */ +} __attribute__ ((packed)) volume_label_t; + + +typedef struct extent { + __u8 typeind; /* extent type indicator */ + __u8 seqno; /* extent sequence number */ + cchh_t llimit; /* starting point of this extent */ + cchh_t ulimit; /* ending point of this extent */ +} __attribute__ ((packed)) extent_t; + + +typedef struct dev_const { + __u16 DS4DSCYL; /* number of logical cyls */ + __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ + __u16 DS4DEVTK; /* device track length */ + __u8 DS4DEVI; /* non-last keyed record overhead */ + __u8 DS4DEVL; /* last keyed record overhead */ + __u8 DS4DEVK; /* non-keyed record overhead differential */ + __u8 DS4DEVFG; /* flag byte */ + __u16 DS4DEVTL; /* device tolerance */ + __u8 DS4DEVDT; /* number of DSCB's per track */ + __u8 DS4DEVDB; /* number of directory blocks per track */ +} __attribute__ ((packed)) dev_const_t; + + +typedef struct format1_label { + char DS1DSNAM[44]; /* data set name */ + __u8 DS1FMTID; /* format identifier */ + char DS1DSSN[6]; /* data set serial number */ + __u16 DS1VOLSQ; /* volume sequence number */ + labeldate_t DS1CREDT; /* creation date: ydd */ + labeldate_t DS1EXPDT; /* expiration date */ + __u8 DS1NOEPV; /* number of extents on volume */ + __u8 DS1NOBDB; /* no. of bytes used in last direction blk */ + __u8 DS1FLAG1; /* flag 1 */ + char DS1SYSCD[13]; /* system code */ + labeldate_t DS1REFD; /* date last referenced */ + __u8 DS1SMSFG; /* system managed storage indicators */ + __u8 DS1SCXTF; /* sec. space extension flag byte */ + __u16 DS1SCXTV; /* secondary space extension value */ + __u8 DS1DSRG1; /* data set organisation byte 1 */ + __u8 DS1DSRG2; /* data set organisation byte 2 */ + __u8 DS1RECFM; /* record format */ + __u8 DS1OPTCD; /* option code */ + __u16 DS1BLKL; /* block length */ + __u16 DS1LRECL; /* record length */ + __u8 DS1KEYL; /* key length */ + __u16 DS1RKP; /* relative key position */ + __u8 DS1DSIND; /* data set indicators */ + __u8 DS1SCAL1; /* secondary allocation flag byte */ + char DS1SCAL3[3]; /* secondary allocation quantity */ + ttr_t DS1LSTAR; /* last used track and block on track */ + __u16 DS1TRBAL; /* space remaining on last used track */ + __u16 res1; /* reserved */ + extent_t DS1EXT1; /* first extent description */ + extent_t DS1EXT2; /* second extent description */ + extent_t DS1EXT3; /* third extent description */ + cchhb_t DS1PTRDS; /* possible pointer to f2 or f3 DSCB */ +} __attribute__ ((packed)) format1_label_t; + + +typedef struct format4_label { + char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ + __u8 DS4IDFMT; /* format identifier */ + cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ + __u16 DS4DSREC; /* number of available DSCB's */ + cchh_t DS4HCCHH; /* CCHH of next available alternate track */ + __u16 DS4NOATK; /* number of remaining alternate tracks */ + __u8 DS4VTOCI; /* VTOC indicators */ + __u8 DS4NOEXT; /* number of extents in VTOC */ + __u8 DS4SMSFG; /* system managed storage indicators */ + __u8 DS4DEVAC; /* number of alternate cylinders. + Subtract from first two bytes of + DS4DEVSZ to get number of usable + cylinders. can be zero. valid + only if DS4DEVAV on. */ + dev_const_t DS4DEVCT; /* device constants */ + char DS4AMTIM[8]; /* VSAM time stamp */ + char DS4AMCAT[3]; /* VSAM catalog indicator */ + char DS4R2TIM[8]; /* VSAM volume/catalog match time stamp */ + char res1[5]; /* reserved */ + char DS4F6PTR[5]; /* pointer to first format 6 DSCB */ + extent_t DS4VTOCE; /* VTOC extent description */ + char res2[10]; /* reserved */ + __u8 DS4EFLVL; /* extended free-space management level */ + cchhb_t DS4EFPTR; /* pointer to extended free-space info */ + char res3[9]; /* reserved */ +} __attribute__ ((packed)) format4_label_t; + + +char * vtoc_ebcdic_enc ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +char * vtoc_ebcdic_dec ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +void vtoc_set_extent ( + extent_t * ext, + __u8 typeind, + __u8 seqno, + cchh_t * lower, + cchh_t * upper); +void vtoc_set_cchh ( + cchh_t * addr, + __u16 cc, + __u16 hh); +void vtoc_set_cchhb ( + cchhb_t * addr, + __u16 cc, + __u16 hh, + __u8 b); +void vtoc_set_date ( + labeldate_t * d, + __u8 year, + __u16 day); + + +int vtoc_read_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +int vtoc_write_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +void vtoc_read_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_write_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_init_format4_label ( + struct hd_geometry *geo, + format4_label_t *f4lbl, + unsigned int usable_partitions, + unsigned int cylinders, + unsigned int tracks, + unsigned int blocks); +void vtoc_init_format1_label ( + char *volid, + unsigned int blksize, + extent_t *part_extent, + format1_label_t *f1); +void vtoc_update_format4_label ( + format4_label_t *f4, + cchhb_t *highest_f1, + __u8 unused_update, + __u16 freespace_update); + + + + + + + + + + + + + + + diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/atomic.h linux/include/asm-s390x/atomic.h --- v2.4.3/linux/include/asm-s390x/atomic.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/atomic.h Wed Apr 11 19:02:29 2001 @@ -5,7 +5,7 @@ * include/asm-s390x/atomic.h * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Denis Joseph Barrow * @@ -25,6 +25,15 @@ #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") +#define __CS_LOOP(old, new, ptr, op_val, op_string) \ + __asm__ __volatile__(" l %0,0(%2)\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%3\n" \ + " cs %0,%1,0(%2)\n" \ + " jl 0b" \ + : "=&d" (old), "=&d" (new) \ + : "a" (ptr), "d" (op_val) : "cc" ); + static __inline__ int atomic_read(atomic_t *v) { int retval; @@ -43,149 +52,80 @@ static __inline__ void atomic_add(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " ar 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "ar"); } static __inline__ int atomic_add_return (int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval; -} - -static __inline__ int atomic_inc_and_test(volatile atomic_t *v) -{ - int i; - - __asm__ __volatile__(" l 0,%0\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,%0\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "cc" ); - return i != 0; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new; } static __inline__ int atomic_add_negative(int i, atomic_t *v) { - int newval; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ar %1,%2\n" - " cs 0,%1,0(1)\n" - " jl 0b\n" - : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "1", "cc" ); - return newval < 0; + int old, new; + __CS_LOOP(old, new, v, i, "ar"); + return new < 0; } static __inline__ void atomic_sub(int i, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " sr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, i, "sr"); } static __inline__ void atomic_inc(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " ahi 1,1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); } static __inline__ int atomic_inc_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ahi %1,1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new; +} + +static __inline__ int atomic_inc_and_test(volatile atomic_t *v) +{ + int old, new; + __CS_LOOP(old, new, v, 1, "ar"); + return new != 0; } static __inline__ void atomic_dec(volatile atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " ahi 1,-1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); } static __inline__ int atomic_dec_return(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); - return i; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new; } static __inline__ int atomic_dec_and_test(volatile atomic_t *v) { - int i; - __asm__ __volatile__(" la 1,%0\n" - " l 0,0(1)\n" - "0: lr %1,0\n" - " ahi %1,-1\n" - " cs 0,%1,0(1)\n" - " jl 0b" - : "+m" (*v), "=&d" (i) : : "0", "1", "cc"); - return i == 0; + int old, new; + __CS_LOOP(old, new, v, 1, "sr"); + return new == 0; } static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " nr 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (~(mask)) - : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, ~mask, "nr"); } static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" la 2,%0\n" - " l 0,0(2)\n" - "0: lr 1,0\n" - " or 1,%1\n" - " cs 0,1,0(2)\n" - " jl 0b" - : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" ); + int old, new; + __CS_LOOP(old, new, v, mask, "or"); } /* @@ -198,14 +138,14 @@ int retval; __asm__ __volatile__( - " la 1,%1\n" " lr 0,%2\n" - " cs 0,%3,0(1)\n" + " cs 0,%3,0(%1)\n" " ipm %0\n" - " srl %0,28" - : "=&r" (retval), "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "0", "1", "cc"); + " srl %0,28\n" + "0:" + : "=&d" (retval) + : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "0", "cc"); return retval; } @@ -216,13 +156,11 @@ atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v) { __asm__ __volatile__( - " la 1,%0\n" "0: lr 0,%1\n" - " cs 0,%2,0(1)\n" + " cs 0,%2,0(%0)\n" " jl 0b\n" - : "+m" (*v) - : "d" (expected_oldval) , "d" (new_val) - : "cc", "0", "1"); + : : "a" (v), "d" (expected_oldval) , "d" (new_val) + : "cc", "0" ); } #define atomic_compare_and_swap_debug(where,from,to) \ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/ccwcache.h linux/include/asm-s390x/ccwcache.h --- v2.4.3/linux/include/asm-s390x/ccwcache.h Fri Mar 2 11:12:06 2001 +++ linux/include/asm-s390x/ccwcache.h Wed Apr 11 19:02:29 2001 @@ -62,6 +62,7 @@ #define CQR_STATUS_DONE 0x04 /* request is completed successfully */ #define CQR_STATUS_ERROR 0x05 /* request is completed with error */ #define CQR_STATUS_FAILED 0x06 /* request is finally failed */ +#define CQR_STATUS_PENDING 0x07 /* request is waiting for interrupt - ERP only */ #define CQR_FLAGS_CHAINED 0x01 /* request is chained by another (last CCW is TIC) */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/chandev.h linux/include/asm-s390x/chandev.h --- v2.4.3/linux/include/asm-s390x/chandev.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/chandev.h Wed Apr 11 19:02:29 2001 @@ -66,6 +66,12 @@ unsigned long irqflags, const char *devname, void *dev_id); +/* + * I originally believed this function wouldn't be necessary + * I subsequently found that reprobing failed in certain cases :-(, + * It is just a wrapper for free irq. + */ +void chandev_free_irq(unsigned int irq, void *dev_id); typedef enum { diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/cpcmd.h linux/include/asm-s390x/cpcmd.h --- v2.4.3/linux/include/asm-s390x/cpcmd.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-s390x/cpcmd.h Wed Apr 11 19:02:29 2001 @@ -0,0 +1,14 @@ +/* + * 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/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h --- v2.4.3/linux/include/asm-s390x/dasd.h Fri Mar 2 11:12:06 2001 +++ linux/include/asm-s390x/dasd.h Wed Apr 11 19:02:29 2001 @@ -5,11 +5,16 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * History of changes (starts July 2000) + * 02/01/01 added dynamic registration of ioctls */ #ifndef DASD_H #define DASD_H +#undef ERP_DEBUG /* enable debug messages */ +#undef ERP_FULL_ERP /* enable full ERP - experimental code !!!! */ +#define CONFIG_DASD_DYNAMIC + #include <linux/ioctl.h> #include <asm/irq.h> @@ -29,6 +34,10 @@ /* translate blocknumber of partition to absolute */ #define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) +typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args); +int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler); +int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler); + #define DASD_NAME "dasd" #define DASD_PARTN_BITS 2 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) @@ -49,6 +58,10 @@ #define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 #define DASD_FORMAT_DEFAULT_INTENSITY -1 +#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 +#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 +#define DASD_FORMAT_INTENS_INVALIDATE 0x04 +#define DASD_FORMAT_INTENS_CDL 0x08 #ifdef __KERNEL__ #include <linux/version.h> #include <linux/major.h> @@ -135,9 +148,15 @@ typedef struct dasd_devreg_t { devreg_t devreg; /* the devreg itself */ /* build a linked list of devregs, needed for cleanup */ - struct dasd_devreg_t *next; + struct list_head list; } dasd_devreg_t; +typedef struct { + struct list_head list; + int no; + dasd_ioctl_fn_t handler; +} dasd_ioctl_list_t; + typedef enum { dasd_era_fatal = -1, /* no chance to recover */ dasd_era_none = 0, /* don't recover, everything alright */ @@ -168,7 +187,7 @@ int d_major = MAJOR(d_device->kdev); \ int d_minor = MINOR(d_device->kdev); \ printk(d_loglevel PRINTK_HEADER \ - "/dev/%s(%d:%d), 0x%04X on SCH 0x%x:" \ + "/dev/%s(%d:%d),%04X IRQ0x%x:" \ d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ } while(0) @@ -181,6 +200,7 @@ unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ + unsigned int pt_block; /* from which block to read the partn table */ } dasd_sizes_t; /* @@ -193,6 +213,38 @@ ccw_req_t *tail; } dasd_chanq_t; +#define DASD_DEVICE_FORMAT_STRING "Device: %p" +#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_event(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); +#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_exception(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); + +#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" +#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_event(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); +#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_exception(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); + struct dasd_device_t; struct request; @@ -230,7 +282,7 @@ typedef struct dasd_discipline_t { char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ - + int max_blocks; /* maximum number of blocks to be chained */ dasd_ck_id_fn_t id_check; /* to check sense data */ dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ @@ -251,9 +303,13 @@ struct dasd_discipline_t *next; /* used for list of disciplines */ } dasd_discipline_t; +#define DASD_MAJOR_INFO_REGISTERED 1 +#define DASD_MAJOR_INFO_IS_STATIC 2 + typedef struct major_info_t { - struct major_info_t *next; + struct list_head list; struct dasd_device_t **dasd_device; + int flags; struct gendisk gendisk; /* actually contains the major number */ } __attribute__ ((packed)) major_info_t; @@ -278,6 +334,7 @@ struct dasd_chanq_t queue; wait_queue_head_t wait_q; request_queue_t request_queue; + struct timer_list timer; devstat_t dev_status; /* needed ONLY!! for request_irq */ dasd_sizes_t sizes; char name[16]; /* The name of the device in /dev */ @@ -300,7 +357,7 @@ #define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 #define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 #define DASD_DEVICE_LEVEL_ANALYSED 0x08 -#define DASD_DEVICE_LEVEL_PARTITIONED 0x10 +#define DASD_DEVICE_LEVEL_ONLINE 0x10 int dasd_init (void); void dasd_discipline_enq (dasd_discipline_t *); @@ -312,8 +369,12 @@ int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); ccw_req_t *dasd_alloc_request (char *, int, int); void dasd_free_request (ccw_req_t *); -int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *); int dasd_oper_handler (int irq, devreg_t * devreg); +void dasd_schedule_bh (dasd_device_t *); + +debug_info_t *dasd_debug_area; #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/debug.h linux/include/asm-s390x/debug.h --- v2.4.3/linux/include/asm-s390x/debug.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/debug.h Wed Apr 11 19:02:29 2001 @@ -19,9 +19,8 @@ struct { unsigned long long clock:52; unsigned long long exception:1; - unsigned long long used:1; - unsigned long long unused:1; - unsigned long long cpuid:9; + unsigned long long level:3; + unsigned long long cpuid:8; } fields; unsigned long long stck; @@ -29,6 +28,9 @@ void* caller; } __attribute__((packed)); + +#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + #ifdef __KERNEL__ #include <linux/version.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) @@ -45,7 +47,6 @@ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ #define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ -#define DEBUG_FEATURE_VERSION 1 /* version of debug feature */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ @@ -103,43 +104,98 @@ debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; debug_input_proc_t* input_proc; + void* private_data; }; extern struct debug_view debug_hex_ascii_view; extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +/* do NOT use the _common functions */ + +debug_entry_t* debug_event_common(debug_info_t* id, int level, + const void* data, int length); + +debug_entry_t* debug_exception_common(debug_info_t* id, int level, + const void* data, int length); + +/* Debug Feature API: */ debug_info_t* debug_register(char* name, int pages_index, int nr_areas, - int buf_size); + int buf_size); + void debug_unregister(debug_info_t* id); void debug_set_level(debug_info_t* id, int new_level); -debug_entry_t* debug_event(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_event(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_event(debug_info_t* id, int level, - const char* txt); - -debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_exception(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_exception(debug_info_t* id, int level, - const char* txt); +extern inline debug_entry_t* +debug_event(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_event(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned int)); +} -static inline debug_entry_t * +extern inline debug_entry_t * debug_long_event (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_event(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_event(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,txt,strlen(txt)); } -static inline debug_entry_t * + +extern debug_entry_t * +debug_sprintf_event(debug_info_t* id,int level,char *string,...); + + +extern inline debug_entry_t* +debug_exception(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_exception(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * debug_long_exception (debug_info_t* id, int level, unsigned long tag) { - unsigned long t=tag; - return debug_exception(id,level,&t,sizeof(unsigned long)); + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_exception(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,txt,strlen(txt)); } + + +extern debug_entry_t * +debug_sprintf_exception(debug_info_t* id,int level,char *string,...); + int debug_register_view(debug_info_t* id, struct debug_view* view); int debug_unregister_view(debug_info_t* id, struct debug_view* view); diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/delay.h linux/include/asm-s390x/delay.h --- v2.4.3/linux/include/asm-s390x/delay.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/delay.h Wed Apr 11 19:02:29 2001 @@ -8,7 +8,7 @@ * Derived from "include/asm-i386/delay.h" * Copyright (C) 1993 Linus Torvalds * - * Delay routines calling functions in arch/i386/lib/delay.c + * Delay routines calling functions in arch/s390x/lib/delay.c */ #ifndef _S390_DELAY_H diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/ebcdic.h linux/include/asm-s390x/ebcdic.h --- v2.4.3/linux/include/asm-s390x/ebcdic.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/ebcdic.h Wed Apr 11 19:02:29 2001 @@ -24,24 +24,18 @@ extern __inline__ void codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr) { - static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 }; + if (nr <= 0) + return; __asm__ __volatile__( - " lgr 1,%0\n" - " lgr 2,%1\n" - " lgr 3,%2\n" - " aghi 2,-256\n" - " jm 1f\n" - "0: tr 0(256,1),0(3)\n" - " aghi 1,256\n" - " aghi 2,-256\n" - " jp 0b\n" - "1: aghi 2,255\n" - " jm 2f\n" - " ex 2,%3\n" - "2:" - : /* no output */ - : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0]) - : "cc", "memory", "1", "2", "3" ); + " bras 1,1f\n" + " tr 0(1,%0),0(%2)\n" + "0: la %0,256(%0)\n" + " tr 0(256,%0),0(%2)\n" + "1: ahi %1,-256\n" + " jp 0b\n" + " ex %1,0(1)" + : "+&a" (addr), "+&a" (nr-1) + : "a" (codepage) : "cc", "memory", "1" ); } #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr) diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/elf.h linux/include/asm-s390x/elf.h --- v2.4.3/linux/include/asm-s390x/elf.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/elf.h Wed Apr 11 19:02:29 2001 @@ -31,7 +31,8 @@ * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(x) \ - ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/irq.h linux/include/asm-s390x/irq.h --- v2.4.3/linux/include/asm-s390x/irq.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/irq.h Wed Apr 11 19:02:29 2001 @@ -1,5 +1,5 @@ -#ifndef __irq_h -#define __irq_h +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H #include <linux/config.h> #ifdef __KERNEL__ @@ -19,28 +19,6 @@ extern int enable_irq(unsigned int); /* - * Interrupt controller descriptor. This is all we need - * to describe about the low-level hardware. - */ -struct hw_interrupt_type { - const __u8 *typename; - int (*handle)(unsigned int irq, - int cpu, - struct pt_regs * regs); - int (*enable) (unsigned int irq); - int (*disable)(unsigned int irq); -}; - -/* - * Status: reason for being disabled: somebody has - * done a "disable_irq()" or we must not re-enter the - * already executing irq.. - */ -#define IRQ_INPROGRESS 1 -#define IRQ_DISABLED 2 -#define IRQ_PENDING 4 - -/* * path management control word */ typedef struct { @@ -86,7 +64,7 @@ __u32 pfch : 1; /* prefetch */ __u32 isic : 1; /* initial-status interruption control */ __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* suppress-suspended interruption */ + __u32 ssi : 1; /* supress-suspended interruption */ __u32 zcc : 1; /* zero condition code */ __u32 ectl : 1; /* extended control */ __u32 pno : 1; /* path not operational */ @@ -186,7 +164,7 @@ typedef struct { __u8 cmd_code;/* command code */ - __u8 flags; /* flags, like IDA addressing, etc. */ + __u8 flags; /* flags, like IDA adressing, etc. */ __u16 count; /* byte count */ __u32 cda; /* data address */ } __attribute__ ((packed,aligned(8))) ccw1_t; @@ -456,24 +434,10 @@ typedef int (* adapter_int_handler_t)( __u32 intparm ); -struct s390_irqaction { - io_handler_func_t handler; - unsigned long flags; - const char *name; - devstat_t *dev_id; -}; - -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. - * - * Pad this out to 32 bytes for cache and indexing reasons. - */ typedef struct { - unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ - struct hw_interrupt_type *handler; /* handle/enable/disable functions */ - struct s390_irqaction *action; /* IRQ action list */ + io_handler_func_t handler; /* interrupt handler routine */ + const char *name; /* device name */ + devstat_t *dev_id; /* device status block */ } irq_desc_t; typedef struct { @@ -531,9 +495,8 @@ /* * do_IO() * - * Start a S/390 channel program. When the interrupt arrives - * handle_IRQ_event() is called, which eventually calls the - * IRQ handler, either immediately, delayed (dev-end missing, + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered - * should never occur, as the IRQ (subchannel ID) should be * disabled if no handler is present. Depending on the action @@ -606,8 +569,6 @@ const char *devname, void *dev_id); -extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); - extern int set_cons_dev(int irq); extern int reset_cons_dev(int irq); extern int wait_cons_dev(int irq); @@ -621,16 +582,13 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "STSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) - : "cc", "1" ); + " lr 1,%1\n" + " stsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000), "a" (addr) + : "cc", "1" ); return ccode; } @@ -639,15 +597,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "MSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " msch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -657,12 +612,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - " lgr 1,%1\n" + " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#ifdef CONFIG_ARCH_S390X ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " jg 1b\n" @@ -671,12 +626,12 @@ " .align 8\n" " .quad 0b,2b\n" ".previous" -#else " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" +#else ".section .fixup,\"ax\"\n" "2: l %0,%3\n" " bras 1,3f\n" @@ -690,7 +645,7 @@ ".previous" #endif : "=d" (ccode) - : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) + : "d" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) : "cc", "1" ); return ccode; } @@ -700,15 +655,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "TSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " tsch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -718,10 +670,11 @@ int ccode; __asm__ __volatile__( - "TPI 0(%1)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " tpi 0(%1)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc", "1" ); return ccode; } @@ -731,15 +684,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "SSCH 0(%2)\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr) + " lr 1,%1\n" + " ssch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L), "a" (addr) : "cc", "1" ); return ccode; } @@ -749,15 +699,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " rsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -767,15 +714,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "CSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " csch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -785,15 +729,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "HSCH\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (irq | 0x10000L) + " lr 1,%1\n" + " hsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (irq | 0x10000L) : "cc", "1" ); return ccode; } @@ -803,9 +744,9 @@ int ccode; __asm__ __volatile__( - "IAC 1\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" + " iac 1\n" + " ipm %0\n" + " srl %0,28" : "=d" (ccode) : : "cc", "1" ); return ccode; } @@ -815,15 +756,12 @@ int ccode; __asm__ __volatile__( -#ifdef CONFIG_ARCH_S390X - "LGR 1,%1\n\t" -#else - "LR 1,%1\n\t" -#endif - "RCHP\n\t" - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "r" (chpid) + " lr 1,%1\n" + " rchp\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "d" (chpid) : "cc", "1" ); return ccode; } @@ -850,16 +788,16 @@ __asm__ __volatile__( #ifdef CONFIG_ARCH_S390X - "SAM31\n\t" - "DIAG %1,0,0x210\n\t" - "SAM64\n\t" -#else - "LR 1,%1\n\t" - ".long 0x83110210\n\t" -#endif - "IPM %0\n\t" - "SRL %0,28\n\t" - : "=d" (ccode) : "a" (addr) + " sam31\n" + " diag %1,0,0x210\n" + " sam64\n" +#else + " diag %1,0,0x210\n" +#endif + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) + : "a" (addr) : "cc" ); return ccode; } @@ -885,15 +823,9 @@ static inline void irq_enter(int cpu, unsigned int irq) { hardirq_enter(cpu); -#ifdef CONFIG_ARCH_S390X while (atomic_read(&global_irq_lock) != 0) { eieio(); } -#else - while (test_bit(0,&global_irq_lock)) { - eieio(); - } -#endif } static inline void irq_exit(int cpu, unsigned int irq) @@ -958,5 +890,8 @@ #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) #endif /* __KERNEL__ */ + +#define touch_nmi_watchdog() do { } while(0) + #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/irqextras390.h linux/include/asm-s390x/irqextras390.h --- v2.4.3/linux/include/asm-s390x/irqextras390.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/irqextras390.h Wed Dec 31 16:00:00 1969 @@ -1,151 +0,0 @@ -/* - * include/asm-s390/irqextras390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#ifndef __irqextras390_h -#define __irqextras390_h - -/* - irqextras390.h by D.J. Barrow - if you are a bitfield fan & are paranoid that ansi dosen't - give hard definitions about the size of an int or long you might - prefer these definitions as an alternative. - -*/ - -#include <linux/types.h> - -typedef struct -{ - unsigned key:4; - unsigned s:1; - unsigned l:1; - unsigned cc:2; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - unsigned z:1; - unsigned e:1; - unsigned n:1; - unsigned zero:1; - - unsigned fc_start:1; - unsigned fc_halt:1; - unsigned fc_clear:1; - - unsigned ac_resume_pending:1; - unsigned ac_start_pending:1; - unsigned ac_halt_pending:1; - unsigned ac_clear_pending:1; - unsigned ac_subchannel_active:1; - unsigned ac_device_active:1; - unsigned ac_suspended:1; - - unsigned sc_alert:1; - unsigned sc_intermediate:1; - unsigned sc_primary:1; - unsigned sc_seconary:1; - unsigned sc_status_pending:1; - - __u32 ccw_address; - - unsigned dev_status_attention:1; - unsigned dev_status_modifier:1; - unsigned dev_status_control_unit_end:1; - unsigned dev_status_busy:1; - unsigned dev_status_channel_end:1; - unsigned dev_status_device_end:1; - unsigned dev_status_unit_check:1; - unsigned dev_status_unit_exception:1; - - unsigned sch_status_program_cont_int:1; - unsigned sch_status_incorrect_length:1; - unsigned sch_status_program_check:1; - unsigned sch_status_protection_check:1; - unsigned sch_status_channel_data_check:1; - unsigned sch_status_channel_control_check:1; - unsigned sch_status_interface_control_check:1; - unsigned sch_status_chaining_check:1; - - __u16 byte_count; -} scsw_bits_t __attribute__((packed)); - -typedef struct -{ - __u32 flags; - __u32 ccw_address; - __u8 dev_status; - __u8 sch_status; - __u16 byte_count; -} scsw_words_t __attribute__((packed)); - -typedef struct -{ - __u8 cmd_code; - - unsigned cd:1; - unsigned cc:1; - unsigned sli:1; - unsigned skip:1; - unsigned pci:1; - unsigned ida:1; - unsigned s:1; - unsigned res1:1; - - __u16 count; - - __u32 ccw_data_address; -} ccw1_bits_t __attribute__((packed,aligned(8))); - -typedef struct -{ - __u32 interruption_parm; - unsigned key:4; - unsigned s:1; - unsigned res1:3; - unsigned f:1; - unsigned p:1; - unsigned i:1; - unsigned a:1; - unsigned u:1; - __u8 lpm; - unsigned l:1; - unsigned res2:7; - ccw1_bits_t *ccw_program_address; -} orb_bits_t __attribute__((packed)); - -void fixchannelprogram(orb_bits_t *orbptr); -void fixccws(ccw1_bits_t *ccwptr); -enum -{ - ccw_write=0x1, - ccw_read=0x2, - ccw_read_backward=0xc, - ccw_control=0x3, - ccw_sense=0x4, - ccw_sense_id=0xe4, - ccw_transfer_in_channel0=0x8, - ccw_transfer_in_channel1=0x8, - ccw_set_x_mode=0xc3, // according to uli's lan notes - ccw_nop=0x3 // according to uli's notes again - // n.b. ccw_control clashes with this - // so I presume its a special case of - // control -}; - - - -#endif - - - - - - - diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/major.h linux/include/asm-s390x/major.h --- v2.4.3/linux/include/asm-s390x/major.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/major.h Wed Dec 31 16:00:00 1969 @@ -1,150 +0,0 @@ -#ifndef _LINUX_MAJOR_H -#define _LINUX_MAJOR_H - -/* - * This file has definitions for major device numbers. - * For the device number assignments, see Documentation/devices.txt. - */ - -/* limits */ - -/* - * Important: Don't change this to 256. Major number 255 is and must be - * reserved for future expansion into a larger dev_t space. - */ -#define MAX_CHRDEV 255 -#define MAX_BLKDEV 255 - -#define UNNAMED_MAJOR 0 -#define MEM_MAJOR 1 -#define RAMDISK_MAJOR 1 -#define FLOPPY_MAJOR 2 -#define PTY_MASTER_MAJOR 2 -#define IDE0_MAJOR 3 -#define PTY_SLAVE_MAJOR 3 -#define HD_MAJOR IDE0_MAJOR -#define TTY_MAJOR 4 -#define TTYAUX_MAJOR 5 -#define LP_MAJOR 6 -#define VCS_MAJOR 7 -#define LOOP_MAJOR 7 -#define SCSI_DISK0_MAJOR 8 -#define SCSI_TAPE_MAJOR 9 -#define MD_MAJOR 9 -#define MISC_MAJOR 10 -#define SCSI_CDROM_MAJOR 11 -#define QIC02_TAPE_MAJOR 12 -#define XT_DISK_MAJOR 13 -#define SOUND_MAJOR 14 -#define CDU31A_CDROM_MAJOR 15 -#define JOYSTICK_MAJOR 15 -#define GOLDSTAR_CDROM_MAJOR 16 -#define OPTICS_CDROM_MAJOR 17 -#define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 -#define MITSUMI_X_CDROM_MAJOR 20 -#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ -#define SCSI_GENERIC_MAJOR 21 -#define Z8530_MAJOR 34 -#define DIGI_MAJOR 23 -#define IDE1_MAJOR 22 -#define DIGICU_MAJOR 22 -#define MITSUMI_CDROM_MAJOR 23 -#define CDU535_CDROM_MAJOR 24 -#define STL_SERIALMAJOR 24 -#define MATSUSHITA_CDROM_MAJOR 25 -#define STL_CALLOUTMAJOR 25 -#define MATSUSHITA_CDROM2_MAJOR 26 -#define QIC117_TAPE_MAJOR 27 -#define MATSUSHITA_CDROM3_MAJOR 27 -#define MATSUSHITA_CDROM4_MAJOR 28 -#define STL_SIOMEMMAJOR 28 -#define ACSI_MAJOR 28 -#define AZTECH_CDROM_MAJOR 29 -#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ -#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ -#define CM206_CDROM_MAJOR 32 -#define IDE2_MAJOR 33 -#define IDE3_MAJOR 34 -#define NETLINK_MAJOR 36 -#define PS2ESDI_MAJOR 36 -#define IDETAPE_MAJOR 37 -#define Z2RAM_MAJOR 37 -#define APBLOCK_MAJOR 38 /* AP1000 Block device */ -#define DDV_MAJOR 39 /* AP1000 DDV block device */ -#define NBD_MAJOR 43 /* Network block device */ -#define RISCOM8_NORMAL_MAJOR 48 -#define DAC960_MAJOR 48 /* 48..55 */ -#define RISCOM8_CALLOUT_MAJOR 49 -#define MKISS_MAJOR 55 -#define DSP56K_MAJOR 55 /* DSP56001 processor device */ - -#define IDE4_MAJOR 56 -#define IDE5_MAJOR 57 - -#define SCSI_DISK1_MAJOR 65 -#define SCSI_DISK2_MAJOR 66 -#define SCSI_DISK3_MAJOR 67 -#define SCSI_DISK4_MAJOR 68 -#define SCSI_DISK5_MAJOR 69 -#define SCSI_DISK6_MAJOR 70 -#define SCSI_DISK7_MAJOR 71 - - -#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ - -#define COMPAQ_SMART2_MAJOR 72 -#define COMPAQ_SMART2_MAJOR1 73 -#define COMPAQ_SMART2_MAJOR2 74 -#define COMPAQ_SMART2_MAJOR3 75 -#define COMPAQ_SMART2_MAJOR4 76 -#define COMPAQ_SMART2_MAJOR5 77 -#define COMPAQ_SMART2_MAJOR6 78 -#define COMPAQ_SMART2_MAJOR7 79 - -#define SPECIALIX_NORMAL_MAJOR 75 -#define SPECIALIX_CALLOUT_MAJOR 76 - -#define DASD_MAJOR 94 - -#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ - -#define MDISK_MAJOR 64 - -#define I2O_MAJOR 80 /* 80->87 */ - -#define IDE6_MAJOR 88 -#define IDE7_MAJOR 89 -#define IDE8_MAJOR 90 -#define IDE9_MAJOR 91 - -#define AURORA_MAJOR 79 - -#define RTF_MAJOR 150 -#define RAW_MAJOR 162 - -#define USB_ACM_MAJOR 166 -#define USB_ACM_AUX_MAJOR 167 -#define USB_CHAR_MAJOR 180 - -#define UNIX98_PTY_MASTER_MAJOR 128 -#define UNIX98_PTY_MAJOR_COUNT 8 -#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) - -/* - * Tests for SCSI devices. - */ - -#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) - -#define SCSI_BLK_MAJOR(M) \ - (SCSI_DISK_MAJOR(M) \ - || (M) == SCSI_CDROM_MAJOR) - -static __inline__ int scsi_blk_major(int m) { - return SCSI_BLK_MAJOR(m); -} - -#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/misc390.h linux/include/asm-s390x/misc390.h --- v2.4.3/linux/include/asm-s390x/misc390.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/misc390.h Wed Dec 31 16:00:00 1969 @@ -1,15 +0,0 @@ -/* - * include/asm-s390/misc390.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - */ - -#define allocaligned2(type,name,number,align) \ - __u8 name##buff[(sizeof(type)*(number+1))-1]; \ - type *name=(type *)(((__u32)(&name##buff[align-1]))&(-align)) - -#define allocaligned(type,name,number) allocaligned2(type,name,number,__alignof__(type)) - -extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs); diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/page.h linux/include/asm-s390x/page.h --- v2.4.3/linux/include/asm-s390x/page.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/page.h Wed Apr 11 19:02:29 2001 @@ -9,6 +9,8 @@ #ifndef _S390_PAGE_H #define _S390_PAGE_H +#include <asm/setup.h> + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -17,12 +19,43 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -/* - * gcc uses builtin, i.e. MVCLE for both operations - */ +static inline void clear_page(void *page) +{ + asm volatile (" lgr 2,%0\n" + " lghi 3,4096\n" + " slgr 1,1\n" + " mvcl 2,0" + : : "a" ((void *) (page)) + : "memory", "1", "2", "3" ); +} -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) -#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +static inline void copy_page(void *to, void *from) +{ + if (MACHINE_HAS_MVPG) + asm volatile (" sgr 0,0\n" + " mvpg %0,%1" + : : "a" ((void *)(to)), "a" ((void *)(from)) + : "memory", "0" ); + else + asm volatile (" mvc 0(256,%0),0(%1)\n" + " mvc 256(256,%0),256(%1)\n" + " mvc 512(256,%0),512(%1)\n" + " mvc 768(256,%0),768(%1)\n" + " mvc 1024(256,%0),1024(%1)\n" + " mvc 1280(256,%0),1280(%1)\n" + " mvc 1536(256,%0),1536(%1)\n" + " mvc 1792(256,%0),1792(%1)\n" + " mvc 2048(256,%0),2048(%1)\n" + " mvc 2304(256,%0),2304(%1)\n" + " mvc 2560(256,%0),2560(%1)\n" + " mvc 2816(256,%0),2816(%1)\n" + " mvc 3072(256,%0),3072(%1)\n" + " mvc 3328(256,%0),3328(%1)\n" + " mvc 3584(256,%0),3584(%1)\n" + " mvc 3840(256,%0),3840(%1)\n" + : : "a"((void *)(to)),"a"((void *)(from)) + : "memory" ); +} #define clear_user_page(page, vaddr) clear_page(page) #define copy_user_page(to, from, vaddr) copy_page(to, from) diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/pgalloc.h linux/include/asm-s390x/pgalloc.h --- v2.4.3/linux/include/asm-s390x/pgalloc.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/pgalloc.h Wed Apr 11 19:02:29 2001 @@ -33,9 +33,11 @@ */ extern __inline__ pgd_t *get_pgd_slow (void) { + pgd_t *ret; int i; - pgd_t *ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2); - if (ret) + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2); + if (ret != NULL) for (i = 0; i < PTRS_PER_PGD; i++) pgd_clear(ret + i); return ret; @@ -77,15 +79,32 @@ #define pgd_free(pgd) free_pgd_fast(pgd) +extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) +{ + pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd); +} + /* * page middle directory allocation/free routines. */ -extern pmd_t empty_bad_pmd_table[]; -extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address); +extern inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) +{ + pmd_t *pmd; + int i; -extern __inline__ pmd_t *get_pmd_fast (void) + pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2); + if (pmd != NULL) { + for (i=0; i < PTRS_PER_PMD; i++) + pmd_clear(pmd+i); + } + return pmd; +} + +extern __inline__ pmd_t * +pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret = (unsigned long *) pmd_quicklist; + if (ret != NULL) { pmd_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; @@ -94,95 +113,67 @@ return (pmd_t *) ret; } -extern __inline__ void free_pmd_fast (pmd_t *pmd) +extern __inline__ void pmd_free_fast (pmd_t *pmd) { - if (pmd == empty_bad_pmd_table) - return; *(unsigned long *) pmd = (unsigned long) pmd_quicklist; pmd_quicklist = (unsigned long *) pmd; pgtable_cache_size += 4; } -extern __inline__ void free_pmd_slow (pmd_t *pmd) +extern __inline__ void pmd_free_slow (pmd_t *pmd) { free_pages((unsigned long) pmd, 2); } -extern __inline__ pmd_t *pmd_alloc (pgd_t *pgd, unsigned long vmaddr) -{ - unsigned long offset; +#define pmd_free(pmd) pmd_free_fast(pmd) - offset = (vmaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *pmd_page = get_pmd_fast(); - - if (!pmd_page) - return get_pmd_slow(pgd, offset); - pgd_set(pgd, pmd_page); - return pmd_page + offset; - } - if (pgd_bad(*pgd)) - BUG(); - return (pmd_t *) pgd_page(*pgd) + offset; +extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) +{ + pmd_val(*pmd) = _PMD_ENTRY | __pa(pte); + pmd_val1(*pmd) = _PMD_ENTRY | __pa(pte+256); } -#define pmd_alloc_kernel(pgd, addr) pmd_alloc(pgd, addr) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) -#define pmd_free(pmd) free_pmd_fast(pmd) - /* * page table entry allocation/free routines. */ -extern pte_t empty_bad_pte_table[]; -extern pte_t *get_pte_slow (pmd_t *pmd, unsigned long address_preadjusted); - -extern __inline__ pte_t *get_pte_fast (void) +extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) { - unsigned long *ret = (unsigned long *) pte_quicklist; + pte_t *pte; + int i; - if (ret != NULL) { - pte_quicklist = (unsigned long *)(*ret); - ret[0] = ret[1]; - pgtable_cache_size--; + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte != NULL) { + for (i=0; i < PTRS_PER_PTE; i++) + pte_clear(pte+i); } - return (pte_t *) ret; + return pte; } -extern __inline__ void free_pte_fast (pte_t *pte) +extern __inline__ pte_t* pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +{ + unsigned long *ret = (unsigned long *) pte_quicklist; + + if (ret != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +extern __inline__ void pte_free_fast (pte_t *pte) { - if (pte == empty_bad_pte_table) - return; *(unsigned long *) pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern __inline__ void free_pte_slow (pte_t *pte) +extern __inline__ void pte_free_slow (pte_t *pte) { free_page((unsigned long) pte); } -extern __inline__ pte_t *pte_alloc (pmd_t *pmd, unsigned long vmaddr) -{ - unsigned long offset; - - offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t *pte_page = get_pte_fast(); - - if (!pte_page) - return get_pte_slow(pmd, offset); - pmd_set(pmd, pte_page); - return pte_page + offset; - } - if (pmd_bad(*pmd)) - BUG(); - return (pte_t *) pmd_page(*pmd) + offset; -} - -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) +#define pte_free(pte) pte_free_fast(pte) extern int do_check_pgt_cache (int, int); @@ -224,11 +215,28 @@ * on each context switch */ -#define flush_tlb() local_flush_tlb() -#define flush_tlb_all() local_flush_tlb() -#define flush_tlb_mm(mm) local_flush_tlb() -#define flush_tlb_page(vma, va) local_flush_tlb() -#define flush_tlb_range(mm, start, end) local_flush_tlb() +static inline void flush_tlb(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_all(void) +{ + local_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + local_flush_tlb(); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + local_flush_tlb(); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + local_flush_tlb(); +} #else @@ -266,11 +274,28 @@ } } -#define flush_tlb() __flush_tlb_mm(current->mm) -#define flush_tlb_all() global_flush_tlb() -#define flush_tlb_mm(mm) __flush_tlb_mm(mm) -#define flush_tlb_page(vma, va) __flush_tlb_mm((vma)->vm_mm) -#define flush_tlb_range(mm, start, end) __flush_tlb_mm(mm) +static inline void flush_tlb(void) +{ + __flush_tlb_mm(current->mm); +} +static inline void flush_tlb_all(void) +{ + global_flush_tlb(); +} +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + __flush_tlb_mm(mm); +} +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + __flush_tlb_mm(vma->vm_mm); +} +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + __flush_tlb_mm(mm); +} #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/pgtable.h linux/include/asm-s390x/pgtable.h --- v2.4.3/linux/include/asm-s390x/pgtable.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/pgtable.h Wed Apr 11 19:02:29 2001 @@ -228,21 +228,41 @@ /* * pgd/pmd/pte query functions */ -extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) != 0; } -extern inline int pgd_none(pgd_t pgd) { return pgd_val(pgd) & _PGD_ENTRY_INV; } +extern inline int pgd_present(pgd_t pgd) +{ + return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY; +} + +extern inline int pgd_none(pgd_t pgd) +{ + return pgd_val(pgd) & _PGD_ENTRY_INV; +} + extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY; } -extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) != 0; } -extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PMD_ENTRY_INV; } +extern inline int pmd_present(pmd_t pmd) +{ + return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY; +} + +extern inline int pmd_none(pmd_t pmd) +{ + return pmd_val(pmd) & _PMD_ENTRY_INV; +} + extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY; } -extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } +extern inline int pte_present(pte_t pte) +{ + return pte_val(pte) & _PAGE_PRESENT; +} + extern inline int pte_none(pte_t pte) { return ((pte_val(pte) & @@ -411,17 +431,6 @@ #define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot) #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT))) - -extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) -{ - pmd_val(*pmdp) = _PMD_ENTRY | __pa(ptep); - pmd_val1(*pmdp) = _PMD_ENTRY | __pa(ptep+256); -} - -extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ - pgd_val(*pgdp) = _PGD_ENTRY | __pa(pmdp); -} #define pmd_page(pmd) \ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/ptrace.h linux/include/asm-s390x/ptrace.h --- v2.4.3/linux/include/asm-s390x/ptrace.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/ptrace.h Wed Apr 11 19:02:29 2001 @@ -8,284 +8,266 @@ #ifndef _S390_PTRACE_H #define _S390_PTRACE_H + +/* + * Offsets in the user_regs_struct. They are used for the ptrace + * system call and in entry.S + */ +#define PT_PSWMASK 0x00 +#define PT_PSWADDR 0x08 +#define PT_GPR0 0x10 +#define PT_GPR1 0x18 +#define PT_GPR2 0x20 +#define PT_GPR3 0x28 +#define PT_GPR4 0x30 +#define PT_GPR5 0x38 +#define PT_GPR6 0x40 +#define PT_GPR7 0x48 +#define PT_GPR8 0x50 +#define PT_GPR9 0x58 +#define PT_GPR10 0x60 +#define PT_GPR11 0x68 +#define PT_GPR12 0x70 +#define PT_GPR13 0x78 +#define PT_GPR14 0x80 +#define PT_GPR15 0x88 +#define PT_ACR0 0x90 +#define PT_ACR1 0x94 +#define PT_ACR2 0x98 +#define PT_ACR3 0x9C +#define PT_ACR4 0xA0 +#define PT_ACR5 0xA4 +#define PT_ACR6 0xA8 +#define PT_ACR7 0xAC +#define PT_ACR8 0xB0 +#define PT_ACR9 0xB4 +#define PT_ACR10 0xB8 +#define PT_ACR11 0xBC +#define PT_ACR12 0xC0 +#define PT_ACR13 0xC4 +#define PT_ACR14 0xC8 +#define PT_ACR15 0xCC +#define PT_ORIGGPR2 0xD0 +#define PT_FPC 0xD8 +#define PT_FPR0 0xE0 +#define PT_FPR1 0xE8 +#define PT_FPR2 0xF0 +#define PT_FPR3 0xF8 +#define PT_FPR4 0x100 +#define PT_FPR5 0x108 +#define PT_FPR6 0x110 +#define PT_FPR7 0x118 +#define PT_FPR8 0x120 +#define PT_FPR9 0x128 +#define PT_FPR10 0x130 +#define PT_FPR11 0x138 +#define PT_FPR12 0x140 +#define PT_FPR13 0x148 +#define PT_FPR14 0x150 +#define PT_FPR15 0x158 +#define PT_CR_9 0x160 +#define PT_CR_10 0x168 +#define PT_CR_11 0x170 +#define PT_IEEE_IP 0x1A8 +#define PT_LASTOFF PT_IEEE_IP +#define PT_ENDREGS 0x1B0-1 + +#define NUM_GPRS 16 +#define NUM_FPRS 16 +#define NUM_CRS 16 +#define NUM_ACRS 16 +#define GPR_SIZE 8 +#define FPR_SIZE 8 +#define FPC_SIZE 4 +#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ +#define CR_SIZE 8 +#define ACR_SIZE 4 + +#define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */ + +#ifndef __ASSEMBLY__ #include <linux/config.h> -#include <asm/s390-regs-common.h> -#include <asm/current.h> +#include <linux/stddef.h> #include <linux/types.h> + +#include <asm/current.h> #include <asm/setup.h> -#include <linux/stddef.h> +/* this typedef defines how a Program Status Word looks like */ +typedef struct +{ + __u64 mask; + __u64 addr; +} psw_t __attribute__ ((aligned(8))); -#define S390_REGS \ -S390_REGS_COMMON \ -addr_t orig_gpr2; +#ifdef __KERNEL__ +#define FIX_PSW(addr) ((unsigned long)(addr)) +#define ADDR_BITS_REMOVE(addr) ((addr)) +#endif +typedef union +{ + float f; + double d; + __u64 ui; + struct + { + __u32 hi; + __u32 lo; + } fp; +} freg_t; + +typedef struct +{ + __u32 fpc; + freg_t fprs[NUM_FPRS]; +} s390_fp_regs; + +#define FPC_EXCEPTION_MASK 0xF8000000 +#define FPC_FLAGS_MASK 0x00F80000 +#define FPC_DXC_MASK 0x0000FF00 +#define FPC_RM_MASK 0x00000003 +#define FPC_VALID_MASK 0xF8F8FF03 + +/* + * The first entries in pt_regs, gdb_pt_regs and user_regs_struct + * are common for all three structures. The s390_regs structure + * covers the common parts. It simplifies copying the common part + * between the three structures. + */ typedef struct { - S390_REGS -} __attribute__ ((packed)) s390_regs; + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; +} s390_regs; +/* + * The pt_regs struct defines the way the registers are stored on + * the stack during a system call. + */ struct pt_regs { - S390_REGS + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; __u32 trap; + __u32 old_ilc; } __attribute__ ((packed)); +/* + * The gdb_pt_regs struct is used instead of the pt_regs structure + * if kernel remote debugging is used. + */ #if CONFIG_REMOTE_DEBUG -typedef struct +struct gdb_pt_regs { - S390_REGS + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; __u32 trap; - addr_t crs[16]; + __u32 crs[16]; s390_fp_regs fp_regs; -} __attribute__ ((packed)) gdb_pt_regs; +}; #endif - +/* + * Now for the program event recording (trace) definitions. + */ typedef struct { - addr_t cr[3]; + __u64 cr[3]; } per_cr_words __attribute__((packed)); #define PER_EM_MASK 0x00000000E8000000UL + typedef struct { - unsigned :32; - unsigned em_branching:1; - unsigned em_instruction_fetch:1; - /* Switching on storage alteration automatically fixes - the storage alteration event bit in the users std. */ - unsigned em_storage_alteration:1; - unsigned em_gpr_alt_unused:1; - unsigned em_store_real_address:1; - unsigned :3; - unsigned branch_addr_ctl:1; - unsigned :1; - unsigned storage_alt_space_ctl:1; - unsigned :5; - unsigned :16; - addr_t starting_addr; - addr_t ending_addr; + unsigned : 32; + unsigned em_branching : 1; + unsigned em_instruction_fetch : 1; + /* + * Switching on storage alteration automatically fixes + * the storage alteration event bit in the users std. + */ + unsigned em_storage_alteration : 1; + unsigned em_gpr_alt_unused : 1; + unsigned em_store_real_address : 1; + unsigned : 3; + unsigned branch_addr_ctl : 1; + unsigned : 1; + unsigned storage_alt_space_ctl : 1; + unsigned : 21; + addr_t starting_addr; + addr_t ending_addr; } per_cr_bits __attribute__((packed)); typedef struct { - __u16 perc_atmid; /* 0x096 */ - addr_t address; /* 0x098 */ - __u8 access_id; /* 0x0a1 */ + __u16 perc_atmid; + addr_t address; + __u8 access_id; } per_lowcore_words __attribute__((packed)); typedef struct { - unsigned perc_branching:1; /* 0x096 */ - unsigned perc_instruction_fetch:1; - unsigned perc_storage_alteration:1; - unsigned perc_gpr_alt_unused:1; - unsigned perc_store_real_address:1; - unsigned :3; - unsigned atmid_psw_bit_31:1; - unsigned atmid_validity_bit:1; - unsigned atmid_psw_bit_32:1; - unsigned atmid_psw_bit_5:1; - unsigned atmid_psw_bit_16:1; - unsigned atmid_psw_bit_17:1; - unsigned ai:2; - addr_t address; /* 0x098 */ - unsigned :4; /* 0x0a1 */ - unsigned access_id:4; + unsigned perc_branching : 1; /* 0x096 */ + unsigned perc_instruction_fetch : 1; + unsigned perc_storage_alteration : 1; + unsigned perc_gpr_alt_unused : 1; + unsigned perc_store_real_address : 1; + unsigned : 3; + unsigned atmid_psw_bit_31 : 1; + unsigned atmid_validity_bit : 1; + unsigned atmid_psw_bit_32 : 1; + unsigned atmid_psw_bit_5 : 1; + unsigned atmid_psw_bit_16 : 1; + unsigned atmid_psw_bit_17 : 1; + unsigned si : 2; + addr_t address; /* 0x098 */ + unsigned : 4; /* 0x0a1 */ + unsigned access_id : 4; } per_lowcore_bits __attribute__((packed)); - -typedef enum -{ - primary_asce, - ar_asce, - secondary_asce, - home_space_asce -} per_ai_codes; - - - typedef struct { - union - { + union { per_cr_words words; per_cr_bits bits; } control_regs __attribute__((packed)); - /* Use these flags instead of setting em_instruction_fetch */ - /* directly they are used so that single stepping can be */ - /* switched on & off while not affecting other tracing */ - unsigned single_step:1; - unsigned instruction_fetch:1; - unsigned :30; - /* These addresses are copied into cr10 & cr11 if single stepping - is switched off */ - addr_t starting_addr; - addr_t ending_addr; - union - { + /* + * Use these flags instead of setting em_instruction_fetch + * directly they are used so that single stepping can be + * switched on & off while not affecting other tracing + */ + unsigned single_step : 1; + unsigned instruction_fetch : 1; + unsigned : 30; + /* + * These addresses are copied into cr10 & cr11 if single + * stepping is switched off + */ + addr_t starting_addr; + addr_t ending_addr; + union { per_lowcore_words words; per_lowcore_bits bits; } lowcore; } per_struct __attribute__((packed)); - - -/* this struct defines the way the registers are stored on the - stack during a system call. If you change the pt_regs structure, - you'll need to change user.h too. - - N.B. if you modify the pt_regs struct the strace command also has to be - modified & recompiled ( just wait till we have gdb going ). - -*/ - -struct user_regs_struct -{ - S390_REGS - s390_fp_regs fp_regs; -/* These per registers are in here so that gdb can modify them itself - * as there is no "official" ptrace interface for hardware watchpoints. - * this is the way intel does it - */ - per_struct per_info; - addr_t ieee_instruction_pointer; - /* Used to give failing instruction back to user for ieee exceptions */ -}; - -typedef struct user_regs_struct user_regs_struct; - -typedef struct pt_regs pt_regs; - -#ifdef __KERNEL__ -#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) -#define instruction_pointer(regs) ((regs)->psw.addr) -extern void show_regs(struct pt_regs * regs); -extern char *task_show_regs(struct task_struct *task, char *buffer); -#endif - - - - - -#define FIX_PSW(addr) ((unsigned long)(addr)) - -#define MULT_PROCPTR_TYPES ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC)) - -typedef struct -{ - long addr; - long toc; -} routine_descriptor; -extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs); -extern __inline__ void -fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs) -{ - regs->psw.addr=FIX_PSW(rdes->addr); - regs->gprs[12]=rdes->toc; -} - -/* - * Compiler optimisation should save this stuff from being non optimal - * & remove uneccessary code ( isnt gcc great DJB. ) - */ - -/*I'm just using this an indicator of what binformat we are using - * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise - * dereferencing incomplete pointer types in with load_toc_binary - */ -#if MULT_PROCPTR_TYPES -#define uses_routine_descriptors() \ -(current->binfmt->load_binary==load_toc_binary) -#else -#if CONFIG_BINFMT_TOC -#define uses_routine_descriptors() 1 -#else -#define uses_routine_descriptors() 0 -#endif -#endif - -#define pt_off(ptreg) offsetof(user_regs_struct,ptreg) -enum -{ - PT_PSWMASK=pt_off(psw.mask), - PT_PSWADDR=pt_off(psw.addr), - PT_GPR0=pt_off(gprs[0]), - PT_GPR1=pt_off(gprs[1]), - PT_GPR2=pt_off(gprs[2]), - PT_GPR3=pt_off(gprs[3]), - PT_GPR4=pt_off(gprs[4]), - PT_GPR5=pt_off(gprs[5]), - PT_GPR6=pt_off(gprs[6]), - PT_GPR7=pt_off(gprs[7]), - PT_GPR8=pt_off(gprs[8]), - PT_GPR9=pt_off(gprs[9]), - PT_GPR10=pt_off(gprs[10]), - PT_GPR11=pt_off(gprs[11]), - PT_GPR12=pt_off(gprs[12]), - PT_GPR13=pt_off(gprs[13]), - PT_GPR14=pt_off(gprs[14]), - PT_GPR15=pt_off(gprs[15]), - PT_ACR0=pt_off(acrs[0]), - PT_ACR1=pt_off(acrs[1]), - PT_ACR2=pt_off(acrs[2]), - PT_ACR3=pt_off(acrs[3]), - PT_ACR4=pt_off(acrs[4]), - PT_ACR5=pt_off(acrs[5]), - PT_ACR6=pt_off(acrs[6]), - PT_ACR7=pt_off(acrs[7]), - PT_ACR8=pt_off(acrs[8]), - PT_ACR9=pt_off(acrs[9]), - PT_ACR10=pt_off(acrs[10]), - PT_ACR11=pt_off(acrs[11]), - PT_ACR12=pt_off(acrs[12]), - PT_ACR13=pt_off(acrs[13]), - PT_ACR14=pt_off(acrs[14]), - PT_ACR15=pt_off(acrs[15]), - PT_ORIGGPR2=pt_off(orig_gpr2), - PT_FPC=pt_off(fp_regs.fpc), -/* - * A nasty fact of life that the ptrace api - * only supports passing of longs. - */ - PT_FPR0=pt_off(fp_regs.fprs[0].d), - PT_FPR1=pt_off(fp_regs.fprs[1].d), - PT_FPR2=pt_off(fp_regs.fprs[2].d), - PT_FPR3=pt_off(fp_regs.fprs[3].d), - PT_FPR4=pt_off(fp_regs.fprs[4].d), - PT_FPR5=pt_off(fp_regs.fprs[5].d), - PT_FPR6=pt_off(fp_regs.fprs[6].d), - PT_FPR7=pt_off(fp_regs.fprs[7].d), - PT_FPR8=pt_off(fp_regs.fprs[8].d), - PT_FPR9=pt_off(fp_regs.fprs[9].d), - PT_FPR10=pt_off(fp_regs.fprs[10].d), - PT_FPR11=pt_off(fp_regs.fprs[11].d), - PT_FPR12=pt_off(fp_regs.fprs[12].d), - PT_FPR13=pt_off(fp_regs.fprs[13].d), - PT_FPR14=pt_off(fp_regs.fprs[14].d), - PT_FPR15=pt_off(fp_regs.fprs[15].d), - PT_CR_9=pt_off(per_info.control_regs.words.cr[0]), - PT_CR_10=pt_off(per_info.control_regs.words.cr[1]), - PT_CR_11=pt_off(per_info.control_regs.words.cr[2]), - PT_IEEE_IP=pt_off(ieee_instruction_pointer), - PT_LASTOFF=PT_IEEE_IP, - PT_ENDREGS=sizeof(user_regs_struct)-1 -}; - -#define PTRACE_AREA \ -__u32 len; \ -addr_t kernel_addr; \ -addr_t process_addr; - typedef struct { - PTRACE_AREA + __u32 len; + addr_t kernel_addr; + addr_t process_addr; } ptrace_area; /* - 390 specific non posix ptrace requests - I chose unusual values so they are unlikely to clash with future ptrace definitions. + * S/390 specific non posix ptrace requests. I chose unusual values so + * they are unlikely to clash with future ptrace definitions. */ #define PTRACE_PEEKUSR_AREA 0x5000 #define PTRACE_POKEUSR_AREA 0x5001 @@ -293,7 +275,10 @@ #define PTRACE_PEEKDATA_AREA 0x5003 #define PTRACE_POKETEXT_AREA 0x5004 #define PTRACE_POKEDATA_AREA 0x5005 -/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */ +/* + * PT_PROT definition is loosely based on hppa bsd definition in + * gdb/hppab-nat.c + */ #define PTRACE_PROT 21 typedef enum @@ -309,18 +294,41 @@ addr_t hiaddr; ptprot_flags prot; } ptprot_area; -#endif - - - - - - - - - +/* Sequence of bytes for breakpoint illegal instruction. */ +#define S390_BREAKPOINT {0x0,0x1} +#define S390_BREAKPOINT_U16 ((__u16)0x0001) +#define S390_SYSCALL_OPCODE ((__u16)0x0a00) +#define S390_SYSCALL_SIZE 2 +/* + * The user_regs_struct defines the way the user registers are + * store on the stack for signal handling. + */ +struct user_regs_struct +{ + psw_t psw; + __u64 gprs[NUM_GPRS]; + __u32 acrs[NUM_ACRS]; + __u64 orig_gpr2; + s390_fp_regs fp_regs; + /* + * These per registers are in here so that gdb can modify them + * itself as there is no "official" ptrace interface for hardware + * watchpoints. This is the way intel does it. + */ + per_struct per_info; + addr_t ieee_instruction_pointer; + /* Used to give failing instruction back to user for ieee exceptions */ +}; +#ifdef __KERNEL__ +#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) +#define instruction_pointer(regs) ((regs)->psw.addr) +extern void show_regs(struct pt_regs * regs); +extern char *task_show_regs(struct task_struct *task, char *buffer); +#endif +#endif /* __ASSEMBLY__ */ +#endif /* _S390X_PTRACE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/queue.h linux/include/asm-s390x/queue.h --- v2.4.3/linux/include/asm-s390x/queue.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/queue.h Wed Apr 11 19:02:29 2001 @@ -7,8 +7,8 @@ * * A little set of queue utilies. */ + #include <linux/stddef.h> -#include <asm/types.h> typedef struct queue { @@ -105,8 +105,8 @@ for(curr=lhead;curr!=NULL;curr=curr->next) if(curr==member) - return(TRUE); - return(FALSE); + return(1); + return(0); } static __inline__ int get_prev(list *lhead,list *member,list **prev) @@ -117,11 +117,11 @@ for(curr=lhead;curr!=NULL;curr=curr->next) { if(curr==member) - return(TRUE); + return(1); *prev=curr; } *prev=NULL; - return(FALSE); + return(0); } @@ -137,9 +137,9 @@ prev->next=member->next; else *lhead=member->next; - return(TRUE); + return(1); } - return(FALSE); + return(0); } static __inline__ int remove_from_queue(qheader *qhead,queue *member) @@ -161,9 +161,9 @@ qhead->tail=NULL; qhead->head=member->next; } - return(TRUE); + return(1); } - return(FALSE); + return(0); } diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/s390dyn.h linux/include/asm-s390x/s390dyn.h --- v2.4.3/linux/include/asm-s390x/s390dyn.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/s390dyn.h Wed Apr 11 19:02:29 2001 @@ -10,6 +10,10 @@ #ifndef __s390dyn_h #define __s390dyn_h +#ifndef _LINUX_LIST_H +#include <linux/list.h> +#endif + struct _devreg; typedef int (* oper_handler_func_t)( int irq, @@ -23,6 +27,7 @@ } __attribute__ ((packed)) devreg_hc_t; typedef struct _devreg { + struct list_head list; union { int devno; devreg_hc_t hc; /* has controller info */ @@ -30,8 +35,6 @@ int flag; oper_handler_func_t oper_func; - struct _devreg *prev; - struct _devreg *next; } devreg_t; #define DEVREG_EXACT_MATCH 0x00000001 diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/s390io.h linux/include/asm-s390x/s390io.h --- v2.4.3/linux/include/asm-s390x/s390io.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/s390io.h Wed Apr 11 19:02:29 2001 @@ -75,7 +75,6 @@ unsigned long qintparm; /* queued interruption parameter */ unsigned long qflag; /* queued flags */ __u8 qlpm; /* queued logical path mask */ - __u32 syncnt; /* sync I/O recursive usage count */ } __attribute__ ((aligned(8))) ioinfo_t; diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/semaphore-helper.h linux/include/asm-s390x/semaphore-helper.h --- v2.4.3/linux/include/asm-s390x/semaphore-helper.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/semaphore-helper.h Wed Dec 31 16:00:00 1969 @@ -1,100 +0,0 @@ -/* - * include/asm-s390/semaphore-helper.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * - * Derived from "include/asm-i386/semaphore-helper.h" - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -#ifndef _S390_SEMAPHORE_HELPER_H -#define _S390_SEMAPHORE_HELPER_H - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * but on the x86 we need an external synchronizer. - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * If we give up we must undo our count-decrease we previously did in down(). - * Subtle: up() can continue to happens and increase the semaphore count - * even during our critical section protected by the spinlock. So - * we must remeber to undo the sem->waking that will be run from - * wake_one_more() some time soon, if the semaphore count become > 0. - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * Implementation details are the same of the interruptible case. - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - } else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/semaphore.h linux/include/asm-s390x/semaphore.h --- v2.4.3/linux/include/asm-s390x/semaphore.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/semaphore.h Tue Apr 17 17:19:31 2001 @@ -14,6 +14,7 @@ #include <asm/system.h> #include <asm/atomic.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -89,103 +90,6 @@ { if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subl'ing - * BIAS once per CPU will result in the long remaining - * negative. - * - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned int write_bias_granted; - volatile unsigned int read_bias_granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -}; - -#define RW_LOCK_BIAS 0x01000000 - -#define __RWSEM_DEBUG_INIT /* */ - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -} - -extern void __down_read_failed(int, struct rw_semaphore *); -extern void __down_write_failed(int, struct rw_semaphore *); -extern void __rwsem_wake(int, struct rw_semaphore *); - -static inline void down_read(struct rw_semaphore *sem) -{ - int count; - count = atomic_dec_return(&sem->count); - if (count < 0) - __down_read_failed(count, sem); -} - -static inline void down_write(struct rw_semaphore *sem) -{ - int count; - count = atomic_add_return (-RW_LOCK_BIAS, &sem->count); - if (count < 0) - __down_write_failed(count, sem); -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -static inline void up_read(struct rw_semaphore *sem) -{ - int count; - count = atomic_inc_return(&sem->count); - if (count == 0) - __rwsem_wake(count, sem); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -static inline void up_write(struct rw_semaphore *sem) -{ - int count; - count = atomic_add_return(RW_LOCK_BIAS, &sem->count); - if (count >= 0 && count < RW_LOCK_BIAS) - __rwsem_wake(count, sem); } #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/setup.h linux/include/asm-s390x/setup.h --- v2.4.3/linux/include/asm-s390x/setup.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/setup.h Wed Apr 11 19:02:29 2001 @@ -8,45 +8,34 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define PARMAREA 0x10400 +#define PARMAREA 0x10400 +#define COMMAND_LINE_SIZE 896 +#define RAMDISK_ORIGIN 0x800000 +#define RAMDISK_SIZE 0x800000 #ifndef __ASSEMBLER__ -#define ORIG_ROOT_DEV (*(unsigned long *) (0x10400)) -#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10408)) -#define MEMORY_SIZE (*(unsigned long *) (0x1040a)) -#define MACHINE_FLAGS (*(unsigned long *) (0x10412)) -#define INITRD_START (*(unsigned long *) (0x1041a)) -#define INITRD_SIZE (*(unsigned long *) (0x10422)) -#define RAMDISK_FLAGS (*(unsigned short *) (0x1042a)) +#define IPL_DEVICE (*(unsigned long *) (0x10400)) +#define INITRD_START (*(unsigned long *) (0x10408)) +#define INITRD_SIZE (*(unsigned long *) (0x10410)) #define COMMAND_LINE ((char *) (0x10480)) -#else - -#define ORIG_ROOT_DEV 0x10400 -#define MOUNT_ROOT_RDONLY 0x10408 -#define MEMORY_SIZE 0x1040a -#define MACHINE_FLAGS 0x10412 -#define INITRD_START 0x1041a -#define INITRD_SIZE 0x10422 -#define RAMDISK_FLAGS 0x1042a -#define COMMAND_LINE 0x10480 - -#endif - -#define COMMAND_LINE_SIZE 896 /* * Machine features detected in head.S */ -#define MACHINE_IS_VM (MACHINE_FLAGS & 1) -#define MACHINE_IS_P390 (MACHINE_FLAGS & 4) +extern unsigned long machine_flags; -#define RAMDISK_ORIGIN 0x800000 -#define RAMDISK_SIZE 0x800000 -#define RAMDISK_BLKSIZE 0x1000 -#define RAMDISK_IMAGE_START_MASK 0x07FF -#define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 +#define MACHINE_IS_VM (machine_flags & 1) +#define MACHINE_IS_P390 (machine_flags & 4) +#define MACHINE_HAS_MVPG (machine_flags & 16) +#else + +#define IPL_DEVICE 0x10400 +#define INITRD_START 0x10408 +#define INITRD_SIZE 0x10410 +#define COMMAND_LINE 0x10480 + +#endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/signal.h linux/include/asm-s390x/signal.h --- v2.4.3/linux/include/asm-s390x/signal.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/signal.h Wed Apr 11 19:02:29 2001 @@ -71,6 +71,7 @@ #define SIGLOST 29 */ #define SIGPWR 30 +#define SIGSYS 31 #define SIGUNUSED 31 /* These should not be considered constants from userland. */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/sigp.h linux/include/asm-s390x/sigp.h --- v2.4.3/linux/include/asm-s390x/sigp.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/sigp.h Wed Apr 11 19:02:29 2001 @@ -15,7 +15,6 @@ #define __SIGP__ #include <asm/ptrace.h> -#include <asm/misc390.h> #include <asm/atomic.h> /* get real cpu address from logical cpu number */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/smp.h linux/include/asm-s390x/smp.h --- v2.4.3/linux/include/asm-s390x/smp.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/smp.h Wed Apr 11 19:02:29 2001 @@ -8,14 +8,24 @@ */ #ifndef __ASM_SMP_H #define __ASM_SMP_H + #include <linux/config.h> -#ifdef CONFIG_SMP -#ifndef __ASSEMBLY__ + +#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__) #include <asm/lowcore.h> -#include <linux/kernel.h> // FOR FASTCALL definition -#define smp_processor_id() (current->processor) +/* + s390 specific smp.c headers + */ +typedef struct +{ + int intresting; + sigp_ccode ccode; + __u32 status; + __u16 cpu; +} sigp_info; + #define NO_PROC_ID 0xFF /* No processor magic marker */ /* @@ -30,7 +40,7 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -extern void count_cpus(void); +#define smp_processor_id() (current->processor) extern __inline__ int cpu_logical_map(int cpu) { @@ -54,25 +64,12 @@ void smp_local_timer_interrupt(struct pt_regs * regs); -/* - s390 specific smp.c headers - */ -typedef struct -{ - int intresting; - sigp_ccode ccode; - __u32 status; - __u16 cpu; -} sigp_info; - -sigp_ccode -smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait); -void smp_ext_call_others(void (*callback)(void *info), void *info, int wait); +sigp_ccode smp_ext_call(int cpu, void (*cb)(void *info), void *info, int wait); +void smp_ext_call_others(void (*cb)(void *info), void *info, int wait); sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig); void smp_ext_bitcall_others(ec_bit_sig sig); int smp_signal_others(sigp_order_code order_code,__u32 parameter, int spin,sigp_info *info); -#endif #endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/spinlock.h linux/include/asm-s390x/spinlock.h --- v2.4.3/linux/include/asm-s390x/spinlock.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/spinlock.h Wed Apr 11 19:02:29 2001 @@ -73,6 +73,8 @@ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) + #define read_lock(rw) \ asm volatile(" la 1,%0\n" \ " lg 2,0(1)\n" \ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/system.h linux/include/asm-s390x/system.h --- v2.4.3/linux/include/asm-s390x/system.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/system.h Wed Apr 11 19:02:29 2001 @@ -33,6 +33,9 @@ #define xchg(ptr,x) \ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(void *)(ptr),sizeof(*(ptr)))) +extern void __misaligned_u16(void); +extern void __misaligned_u32(void); +extern void __misaligned_u64(void); static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { @@ -43,14 +46,14 @@ " nr 1,%0\n" /* isolate last 2 bits */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,8,%1\n" /* for ptr&3 == 0 */ - " stcm 0,8,%1\n" - " icm 1,4,%1\n" /* for ptr&3 == 1 */ - " stcm 0,4,%1\n" - " icm 1,2,%1\n" /* for ptr&3 == 2 */ - " stcm 0,2,%1\n" - " icm 1,1,%1\n" /* for ptr&3 == 3 */ - " stcm 0,1,%1\n" + " icm 1,8,7(%1)\n" /* for ptr&3 == 0 */ + " stcm 0,8,7(%1)\n" + " icm 1,4,7(%1)\n" /* for ptr&3 == 1 */ + " stcm 0,4,7(%1)\n" + " icm 1,2,7(%1)\n" /* for ptr&3 == 2 */ + " stcm 0,2,7(%1)\n" + " icm 1,1,7(%1)\n" /* for ptr&3 == 3 */ + " stcm 0,1,7(%1)\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -59,20 +62,21 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+&a" (ptr), "+m" (x) : + : "+&a" (ptr) : "a" (&x) : "memory", "0", "1", "2"); + break; case 2: if(((addr_t)ptr)&1) - panic("misaligned (__u16 *) in __xchg\n"); + __misaligned_u16(); asm volatile ( " lghi 1,2\n" " nr 1,%0\n" /* isolate bit 2^1 */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,12,%1\n" /* for ptr&2 == 0 */ - " stcm 0,12,%1\n" - " icm 1,3,%1\n" /* for ptr&2 == 1 */ - " stcm 0,3,%1\n" + " icm 1,12,6(%1)\n" /* for ptr&2 == 0 */ + " stcm 0,12,6(%1)\n" + " icm 1,3,2(%1)\n" /* for ptr&2 == 1 */ + " stcm 0,3,2(%1)\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -81,12 +85,12 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+&a" (ptr), "+m" (x) : + : "+&a" (ptr) : "a" (&x) : "memory", "0", "1", "2"); break; case 4: if(((addr_t)ptr)&3) - panic("misaligned (__u32 *) in __xchg\n"); + __misaligned_u32(); asm volatile ( " l 0,0(%1)\n" "0: cs 0,%0,0(%1)\n" @@ -97,7 +101,7 @@ break; case 8: if(((addr_t)ptr)&7) - panic("misaligned (__u64 *) in __xchg\n"); + __misaligned_u64(); asm volatile ( " lg 0,0(%1)\n" "0: csg 0,%0,0(%1)\n" diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/termios.h linux/include/asm-s390x/termios.h --- v2.4.3/linux/include/asm-s390x/termios.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/termios.h Wed Apr 11 19:02:29 2001 @@ -60,7 +60,7 @@ #define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ -#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/todclk.h linux/include/asm-s390x/todclk.h --- v2.4.3/linux/include/asm-s390x/todclk.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/todclk.h Wed Apr 11 19:02:29 2001 @@ -10,10 +10,14 @@ #ifndef __ASM_TODCLK_H #define __ASM_TODCLK_H +#ifdef __KERNEL__ + #define TOD_uSEC (0x1000ULL) #define TOD_mSEC (1000 * TOD_uSEC) #define TOD_SEC (1000 * TOD_mSEC) #define TOD_MIN (60 * TOD_SEC) #define TOD_HOUR (60 * TOD_MIN) + +#endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/types.h linux/include/asm-s390x/types.h --- v2.4.3/linux/include/asm-s390x/types.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/types.h Wed Apr 11 19:02:29 2001 @@ -41,14 +41,6 @@ */ #ifdef __KERNEL__ -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - typedef signed char s8; typedef unsigned char u8; diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/uaccess.h linux/include/asm-s390x/uaccess.h --- v2.4.3/linux/include/asm-s390x/uaccess.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/uaccess.h Wed Apr 11 19:02:29 2001 @@ -432,21 +432,20 @@ " sacf 512\n" "0: ic 3,0(%0,4)\n" "1: stc 3,0(%0,2)\n" + " ltr 3,3\n" + " jz 2f\n" " aghi %0,1\n" " cgr %0,%3\n" - " je 2f\n" - " ltr 3,3\n" - " jne 0b\n" + " jl 0b\n" "2: sacf 0\n" - "3:\n" ".section .fixup,\"ax\"\n" - "4: lghi %0,%h4\n" - " jg 3b\n" + "3: lghi %0,%h4\n" + " jg 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 8\n" - " .quad 0b,4b\n" - " .quad 1b,4b\n" + " .quad 0b,3b\n" + " .quad 1b,3b\n" ".previous" : "=&a" (len) : "a" (dst), "d" (src), "d" (count), diff -u --recursive --new-file v2.4.3/linux/include/asm-s390x/vtoc.h linux/include/asm-s390x/vtoc.h --- v2.4.3/linux/include/asm-s390x/vtoc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-s390x/vtoc.h Wed Apr 11 19:02:29 2001 @@ -0,0 +1,234 @@ +#ifndef __KERNEL__ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> + +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/hdreg.h> +#include <linux/version.h> +#endif +#include <asm/dasd.h> + +#define LINE_LENGTH 80 +#define VTOC_START_CC 0x0 +#define VTOC_START_HH 0x1 + +enum failure {unable_to_open, + unable_to_seek, + unable_to_write, + unable_to_read}; + +typedef struct ttr { + __u16 tt; + __u8 r; +} __attribute__ ((packed)) ttr_t; + +typedef struct cchhb { + __u16 cc; + __u16 hh; + __u8 b; +} __attribute__ ((packed)) cchhb_t; + +typedef struct cchh { + __u16 cc; + __u16 hh; +} __attribute__ ((packed)) cchh_t; + +typedef struct labeldate { + __u8 year; + __u16 day; +} __attribute__ ((packed)) labeldate_t; + + +typedef struct volume_label { + char volkey[4]; /* volume key = volume label */ + char vollbl[4]; /* volume label */ + char volid[6]; /* volume identifier */ + __u8 security; /* security byte */ + cchhb_t vtoc; /* VTOC address */ + char res1[5]; /* reserved */ + char cisize[4]; /* CI-size for FBA,... */ + /* ...blanks for CKD */ + char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */ + char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */ + char res2[4]; /* reserved */ + char lvtoc[14]; /* owner code for LVTOC */ + char res3[29]; /* reserved */ +} __attribute__ ((packed)) volume_label_t; + + +typedef struct extent { + __u8 typeind; /* extent type indicator */ + __u8 seqno; /* extent sequence number */ + cchh_t llimit; /* starting point of this extent */ + cchh_t ulimit; /* ending point of this extent */ +} __attribute__ ((packed)) extent_t; + + +typedef struct dev_const { + __u16 DS4DSCYL; /* number of logical cyls */ + __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ + __u16 DS4DEVTK; /* device track length */ + __u8 DS4DEVI; /* non-last keyed record overhead */ + __u8 DS4DEVL; /* last keyed record overhead */ + __u8 DS4DEVK; /* non-keyed record overhead differential */ + __u8 DS4DEVFG; /* flag byte */ + __u16 DS4DEVTL; /* device tolerance */ + __u8 DS4DEVDT; /* number of DSCB's per track */ + __u8 DS4DEVDB; /* number of directory blocks per track */ +} __attribute__ ((packed)) dev_const_t; + + +typedef struct format1_label { + char DS1DSNAM[44]; /* data set name */ + __u8 DS1FMTID; /* format identifier */ + char DS1DSSN[6]; /* data set serial number */ + __u16 DS1VOLSQ; /* volume sequence number */ + labeldate_t DS1CREDT; /* creation date: ydd */ + labeldate_t DS1EXPDT; /* expiration date */ + __u8 DS1NOEPV; /* number of extents on volume */ + __u8 DS1NOBDB; /* no. of bytes used in last direction blk */ + __u8 DS1FLAG1; /* flag 1 */ + char DS1SYSCD[13]; /* system code */ + labeldate_t DS1REFD; /* date last referenced */ + __u8 DS1SMSFG; /* system managed storage indicators */ + __u8 DS1SCXTF; /* sec. space extension flag byte */ + __u16 DS1SCXTV; /* secondary space extension value */ + __u8 DS1DSRG1; /* data set organisation byte 1 */ + __u8 DS1DSRG2; /* data set organisation byte 2 */ + __u8 DS1RECFM; /* record format */ + __u8 DS1OPTCD; /* option code */ + __u16 DS1BLKL; /* block length */ + __u16 DS1LRECL; /* record length */ + __u8 DS1KEYL; /* key length */ + __u16 DS1RKP; /* relative key position */ + __u8 DS1DSIND; /* data set indicators */ + __u8 DS1SCAL1; /* secondary allocation flag byte */ + char DS1SCAL3[3]; /* secondary allocation quantity */ + ttr_t DS1LSTAR; /* last used track and block on track */ + __u16 DS1TRBAL; /* space remaining on last used track */ + __u16 res1; /* reserved */ + extent_t DS1EXT1; /* first extent description */ + extent_t DS1EXT2; /* second extent description */ + extent_t DS1EXT3; /* third extent description */ + cchhb_t DS1PTRDS; /* possible pointer to f2 or f3 DSCB */ +} __attribute__ ((packed)) format1_label_t; + + +typedef struct format4_label { + char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ + __u8 DS4IDFMT; /* format identifier */ + cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ + __u16 DS4DSREC; /* number of available DSCB's */ + cchh_t DS4HCCHH; /* CCHH of next available alternate track */ + __u16 DS4NOATK; /* number of remaining alternate tracks */ + __u8 DS4VTOCI; /* VTOC indicators */ + __u8 DS4NOEXT; /* number of extents in VTOC */ + __u8 DS4SMSFG; /* system managed storage indicators */ + __u8 DS4DEVAC; /* number of alternate cylinders. + Subtract from first two bytes of + DS4DEVSZ to get number of usable + cylinders. can be zero. valid + only if DS4DEVAV on. */ + dev_const_t DS4DEVCT; /* device constants */ + char DS4AMTIM[8]; /* VSAM time stamp */ + char DS4AMCAT[3]; /* VSAM catalog indicator */ + char DS4R2TIM[8]; /* VSAM volume/catalog match time stamp */ + char res1[5]; /* reserved */ + char DS4F6PTR[5]; /* pointer to first format 6 DSCB */ + extent_t DS4VTOCE; /* VTOC extent description */ + char res2[10]; /* reserved */ + __u8 DS4EFLVL; /* extended free-space management level */ + cchhb_t DS4EFPTR; /* pointer to extended free-space info */ + char res3[9]; /* reserved */ +} __attribute__ ((packed)) format4_label_t; + + +char * vtoc_ebcdic_enc ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +char * vtoc_ebcdic_dec ( + unsigned char source[LINE_LENGTH], + unsigned char target[LINE_LENGTH], + int l); +void vtoc_set_extent ( + extent_t * ext, + __u8 typeind, + __u8 seqno, + cchh_t * lower, + cchh_t * upper); +void vtoc_set_cchh ( + cchh_t * addr, + __u16 cc, + __u16 hh); +void vtoc_set_cchhb ( + cchhb_t * addr, + __u16 cc, + __u16 hh, + __u8 b); +void vtoc_set_date ( + labeldate_t * d, + __u8 year, + __u16 day); + + +int vtoc_read_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +int vtoc_write_volume_label ( + char * device, + unsigned long vlabel_start, + volume_label_t * vlabel); +void vtoc_read_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_write_label ( + char *device, + unsigned long position, + format4_label_t *f4, + format1_label_t *f1); +void vtoc_init_format4_label ( + struct hd_geometry *geo, + format4_label_t *f4lbl, + unsigned int usable_partitions, + unsigned int cylinders, + unsigned int tracks, + unsigned int blocks); +void vtoc_init_format1_label ( + char *volid, + unsigned int blksize, + extent_t *part_extent, + format1_label_t *f1); +void vtoc_update_format4_label ( + format4_label_t *f4, + cchhb_t *highest_f1, + __u8 unused_update, + __u16 freespace_update); + + + + + + + + + + + + + + + diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h --- v2.4.3/linux/include/asm-sh/bugs.h Thu Jan 4 13:19:13 2001 +++ linux/include/asm-sh/bugs.h Wed Apr 11 21:24:52 2001 @@ -34,6 +34,10 @@ *p++ = '4'; printk("CPU: SH7750\n"); break; + case CPU_ST40STB1: + *p++ = '4'; + printk("CPU: ST40STB1\n"); + break; default: printk("CPU: ??????\n"); break; diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/ec3104.h linux/include/asm-sh/ec3104.h --- v2.4.3/linux/include/asm-sh/ec3104.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/ec3104.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,43 @@ +#ifndef __ASM_EC3104_H +#define __ASM_EC3104_H + + +/* + * Most of the register set is at 0xb0ec0000 - 0xb0ecffff. + * + * as far as I've figured it out the register map is: + * 0xb0ec0000 - id string + * 0xb0ec0XXX - power management + * 0xb0ec1XXX - interrupt control + * 0xb0ec3XXX - ps2 port (touch pad on aero 8000) + * 0xb0ec6XXX - i2c + * 0xb0ec7000 - first serial port (proprietary connector on aero 8000) + * 0xb0ec8000 - second serial port + * 0xb0ec9000 - third serial port + * 0xb0eca000 - fourth serial port (keyboard controller on aero 8000) + * 0xb0eccXXX - GPIO + * 0xb0ecdXXX - GPIO + */ + +#define EC3104_BASE 0xb0ec0000 + +#define EC3104_SER4_DATA (EC3104_BASE+0xa000) +#define EC3104_SER4_IIR (EC3104_BASE+0xa008) +#define EC3104_SER4_MCR (EC3104_BASE+0xa010) +#define EC3104_SER4_LSR (EC3104_BASE+0xa014) +#define EC3104_SER4_MSR (EC3104_BASE+0xa018) + +/* + * our ISA bus. this seems to be real ISA. + */ +#define EC3104_ISA_BASE 0xa5000000 + +#define EC3104_IRQ 11 +#define EC3104_IRQBASE 64 + +#define EC3104_IRQ_SER1 EC3104_IRQBASE + 7 +#define EC3104_IRQ_SER2 EC3104_IRQBASE + 8 +#define EC3104_IRQ_SER3 EC3104_IRQBASE + 9 +#define EC3104_IRQ_SER4 EC3104_IRQBASE + 10 + +#endif /* __ASM_EC3104_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/hd64461.h linux/include/asm-sh/hd64461.h --- v2.4.3/linux/include/asm-sh/hd64461.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/hd64461.h Wed Apr 11 21:24:52 2001 @@ -11,10 +11,22 @@ #define HD64461_SYSCR 0x10002 #define HD64461_SCPUCR 0x10004 -#define HD64461_CPTWAR 0x11030 -#define HD64461_CPTWDR 0x11032 -#define HD64461_CPTRAR 0x11034 -#define HD64461_CPTRDR 0x11036 +#define HD64461_LCDCBAR 0x11000 +#define HD64461_LCDCLOR 0x11002 +#define HD64461_LCDCCRR 0x11004 +#define HD64461_LDR1 0x11010 +#define HD64461_LDR2 0x11012 +#define HD64461_LDHNCR 0x11014 +#define HD64461_LDHNSR 0x11016 +#define HD64461_LDVNTR 0x11018 +#define HD64461_LDVNDR 0x1101a +#define HD64461_LDVSPR 0x1101c +#define HD64461_LDR3 0x1101e + +#define HD64461_CPTWAR 0x11030 +#define HD64461_CPTWDR 0x11032 +#define HD64461_CPTRAR 0x11034 +#define HD64461_CPTRDR 0x11036 #define HD64461_PCC0ISR 0x12000 #define HD64461_PCC0GCR 0x12002 @@ -30,6 +42,23 @@ #define HD64461_P1OCR 0x1202c #define HD64461_PGCR 0x1202e +#define HD64461_GPACR 0x14000 +#define HD64461_GPBCR 0x14002 +#define HD64461_GPCCR 0x14004 +#define HD64461_GPDCR 0x14006 +#define HD64461_GPADR 0x14010 +#define HD64461_GPBDR 0x14012 +#define HD64461_GPCDR 0x14014 +#define HD64461_GPDDR 0x14016 +#define HD64461_GPAICR 0x14020 +#define HD64461_GPBICR 0x14022 +#define HD64461_GPCICR 0x14024 +#define HD64461_GPDICR 0x14026 +#define HD64461_GPAISR 0x14040 +#define HD64461_GPBISR 0x14042 +#define HD64461_GPCISR 0x14044 +#define HD64461_GPDISR 0x14046 + #define HD64461_NIRR 0x15000 #define HD64461_NIMR 0x15002 @@ -40,6 +69,6 @@ #define CONFIG_HD64461_IRQ 36 #endif -#define HD64461_IRQBASE 64 +#define HD64461_IRQBASE OFFCHIP_IRQ_BASE #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/hd64465.h linux/include/asm-sh/hd64465.h --- v2.4.3/linux/include/asm-sh/hd64465.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/hd64465.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,257 @@ +#ifndef _ASM_SH_HD64465_ +#define _ASM_SH_HD64465_ 1 +/* + * $Id: hd64465.h,v 1.3 2001/02/07 18:31:20 stuart_menefy Exp $ + * + * Hitachi HD64465 companion chip support + * + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc. + * + * Derived from <asm/hd64461.h> which bore the message: + * Copyright (C) 2000 YAEGASHI Takeshi + */ +#include <linux/config.h> +#include <asm/io.h> +#include <asm/irq.h> + +/* + * Note that registers are defined here as virtual port numbers, + * which have no meaning except to get translated by hd64465_isa_port2addr() + * to an address in the range 0xb0000000-0xb3ffffff. Note that + * this translation happens to consist of adding the lower 16 bits + * of the virtual port number to 0xb0000000. Note also that the manual + * shows addresses as absolute physical addresses starting at 0x10000000, + * so e.g. the NIRR register is listed as 0x15000 here, 0x10005000 in the + * manual, and accessed using address 0xb0005000 - Greg. + */ + +/* System registers */ +#define HD64465_REG_SRR 0x1000c /* System Revision Register */ +#define HD64465_REG_SDID 0x10010 /* System Device ID Reg */ +#define HD64465_SDID 0x8122 /* 64465 device ID */ + +/* Power Management registers */ +#define HD64465_REG_SMSCR 0x10000 /* System Module Standby Control Reg */ +#define HD64465_SMSCR_PS2ST 0x4000 /* PS/2 Standby */ +#define HD64465_SMSCR_ADCST 0x1000 /* ADC Standby */ +#define HD64465_SMSCR_UARTST 0x0800 /* UART Standby */ +#define HD64465_SMSCR_SCDIST 0x0200 /* Serial Codec Standby */ +#define HD64465_SMSCR_PPST 0x0100 /* Parallel Port Standby */ +#define HD64465_SMSCR_PC0ST 0x0040 /* PCMCIA0 Standby */ +#define HD64465_SMSCR_PC1ST 0x0020 /* PCMCIA1 Standby */ +#define HD64465_SMSCR_AFEST 0x0010 /* AFE Standby */ +#define HD64465_SMSCR_TM0ST 0x0008 /* Timer0 Standby */ +#define HD64465_SMSCR_TM1ST 0x0004 /* Timer1 Standby */ +#define HD64465_SMSCR_IRDAST 0x0002 /* IRDA Standby */ +#define HD64465_SMSCR_KBCST 0x0001 /* Keyboard Controller Standby */ + +/* Interrupt Controller registers */ +#define HD64465_REG_NIRR 0x15000 /* Interrupt Request Register */ +#define HD64465_REG_NIMR 0x15002 /* Interrupt Mask Register */ +#define HD64465_REG_NITR 0x15004 /* Interrupt Trigger Mode Register */ + +/* Timer registers */ +#define HD64465_REG_TCVR1 0x16000 /* Timer 1 constant value register */ +#define HD64465_REG_TCVR0 0x16002 /* Timer 0 constant value register */ +#define HD64465_REG_TRVR1 0x16004 /* Timer 1 read value register */ +#define HD64465_REG_TRVR0 0x16006 /* Timer 0 read value register */ +#define HD64465_REG_TCR1 0x16008 /* Timer 1 control register */ +#define HD64465_REG_TCR0 0x1600A /* Timer 0 control register */ +#define HD64465_TCR_EADT 0x10 /* Enable ADTRIG# signal */ +#define HD64465_TCR_ETMO 0x08 /* Enable TMO signal */ +#define HD64465_TCR_PST_MASK 0x06 /* Clock Prescale */ +#define HD64465_TCR_PST_1 0x06 /* 1:1 */ +#define HD64465_TCR_PST_4 0x04 /* 1:4 */ +#define HD64465_TCR_PST_8 0x02 /* 1:8 */ +#define HD64465_TCR_PST_16 0x00 /* 1:16 */ +#define HD64465_TCR_TSTP 0x01 /* Start/Stop timer */ +#define HD64465_REG_TIRR 0x1600C /* Timer interrupt request register */ +#define HD64465_REG_TIDR 0x1600E /* Timer interrupt disable register */ +#define HD64465_REG_PWM1CS 0x16010 /* PWM 1 clock scale register */ +#define HD64465_REG_PWM1LPC 0x16012 /* PWM 1 low pulse width counter register */ +#define HD64465_REG_PWM1HPC 0x16014 /* PWM 1 high pulse width counter register */ +#define HD64465_REG_PWM0CS 0x16018 /* PWM 0 clock scale register */ +#define HD64465_REG_PWM0LPC 0x1601A /* PWM 0 low pulse width counter register */ +#define HD64465_REG_PWM0HPC 0x1601C /* PWM 0 high pulse width counter register */ + +/* Analog/Digital Converter registers */ +#define HD64465_REG_ADDRA 0x1E000 /* A/D data register A */ +#define HD64465_REG_ADDRB 0x1E002 /* A/D data register B */ +#define HD64465_REG_ADDRC 0x1E004 /* A/D data register C */ +#define HD64465_REG_ADDRD 0x1E006 /* A/D data register D */ +#define HD64465_REG_ADCSR 0x1E008 /* A/D control/status register */ +#define HD64465_ADCSR_ADF 0x80 /* A/D End Flag */ +#define HD64465_ADCSR_ADST 0x40 /* A/D Start Flag */ +#define HD64465_ADCSR_ADIS 0x20 /* A/D Interrupt Status */ +#define HD64465_ADCSR_TRGE 0x10 /* A/D Trigger Enable */ +#define HD64465_ADCSR_ADIE 0x08 /* A/D Interrupt Enable */ +#define HD64465_ADCSR_SCAN 0x04 /* A/D Scan Mode */ +#define HD64465_ADCSR_CH_MASK 0x03 /* A/D Channel */ +#define HD64465_REG_ADCALCR 0x1E00A /* A/D calibration sample control */ +#define HD64465_REG_ADCAL 0x1E00C /* A/D calibration data register */ + + +/* General Purpose I/O ports registers */ +#define HD64465_REG_GPACR 0x14000 /* Port A Control Register */ +#define HD64465_REG_GPBCR 0x14002 /* Port B Control Register */ +#define HD64465_REG_GPCCR 0x14004 /* Port C Control Register */ +#define HD64465_REG_GPDCR 0x14006 /* Port D Control Register */ +#define HD64465_REG_GPECR 0x14008 /* Port E Control Register */ +#define HD64465_REG_GPADR 0x14010 /* Port A Data Register */ +#define HD64465_REG_GPBDR 0x14012 /* Port B Data Register */ +#define HD64465_REG_GPCDR 0x14014 /* Port C Data Register */ +#define HD64465_REG_GPDDR 0x14016 /* Port D Data Register */ +#define HD64465_REG_GPEDR 0x14018 /* Port E Data Register */ +#define HD64465_REG_GPAICR 0x14020 /* Port A Interrupt Control Register */ +#define HD64465_REG_GPBICR 0x14022 /* Port B Interrupt Control Register */ +#define HD64465_REG_GPCICR 0x14024 /* Port C Interrupt Control Register */ +#define HD64465_REG_GPDICR 0x14026 /* Port D Interrupt Control Register */ +#define HD64465_REG_GPEICR 0x14028 /* Port E Interrupt Control Register */ +#define HD64465_REG_GPAISR 0x14040 /* Port A Interrupt Status Register */ +#define HD64465_REG_GPBISR 0x14042 /* Port B Interrupt Status Register */ +#define HD64465_REG_GPCISR 0x14044 /* Port C Interrupt Status Register */ +#define HD64465_REG_GPDISR 0x14046 /* Port D Interrupt Status Register */ +#define HD64465_REG_GPEISR 0x14048 /* Port E Interrupt Status Register */ + +/* PCMCIA bridge interface */ +#define HD64465_REG_PCC0ISR 0x12000 /* socket 0 interface status */ +#define HD64465_PCCISR_PREADY 0x80 /* mem card ready / io card IREQ */ +#define HD64465_PCCISR_PIREQ 0x80 +#define HD64465_PCCISR_PMWP 0x40 /* mem card write-protected */ +#define HD64465_PCCISR_PVS2 0x20 /* voltage select pin 2 */ +#define HD64465_PCCISR_PVS1 0x10 /* voltage select pin 1 */ +#define HD64465_PCCISR_PCD_MASK 0x0c /* card detect */ +#define HD64465_PCCISR_PBVD_MASK 0x03 /* battery voltage */ +#define HD64465_PCCISR_PBVD_BATGOOD 0x03 /* battery good */ +#define HD64465_PCCISR_PBVD_BATWARN 0x01 /* battery low warning */ +#define HD64465_PCCISR_PBVD_BATDEAD1 0x02 /* battery dead */ +#define HD64465_PCCISR_PBVD_BATDEAD2 0x00 /* battery dead */ +#define HD64465_REG_PCC0GCR 0x12002 /* socket 0 general control */ +#define HD64465_PCCGCR_PDRV 0x80 /* output drive */ +#define HD64465_PCCGCR_PCCR 0x40 /* PC card reset */ +#define HD64465_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */ +#define HD64465_PCCGCR_PVCC0 0x10 /* voltage control pin VCC0SEL0 */ +#define HD64465_PCCGCR_PMMOD 0x08 /* memory mode */ +#define HD64465_PCCGCR_PPA25 0x04 /* pin A25 */ +#define HD64465_PCCGCR_PPA24 0x02 /* pin A24 */ +#define HD64465_PCCGCR_PREG 0x01 /* ping PCC0REG# */ +#define HD64465_REG_PCC0CSCR 0x12004 /* socket 0 card status change */ +#define HD64465_PCCCSCR_PSCDI 0x80 /* sw card detect intr */ +#define HD64465_PCCCSCR_PSWSEL 0x40 /* power select */ +#define HD64465_PCCCSCR_PIREQ 0x20 /* IREQ intr req */ +#define HD64465_PCCCSCR_PSC 0x10 /* STSCHG (status change) pin */ +#define HD64465_PCCCSCR_PCDC 0x08 /* CD (card detect) change */ +#define HD64465_PCCCSCR_PRC 0x04 /* ready change */ +#define HD64465_PCCCSCR_PBW 0x02 /* battery warning change */ +#define HD64465_PCCCSCR_PBD 0x01 /* battery dead change */ +#define HD64465_REG_PCC0CSCIER 0x12006 /* socket 0 card status change interrupt enable */ +#define HD64465_PCCCSCIER_PCRE 0x80 /* change reset enable */ +#define HD64465_PCCCSCIER_PIREQE_MASK 0x60 /* IREQ enable */ +#define HD64465_PCCCSCIER_PIREQE_DISABLED 0x00 /* IREQ disabled */ +#define HD64465_PCCCSCIER_PIREQE_LEVEL 0x20 /* IREQ level-triggered */ +#define HD64465_PCCCSCIER_PIREQE_FALLING 0x40 /* IREQ falling-edge-trig */ +#define HD64465_PCCCSCIER_PIREQE_RISING 0x60 /* IREQ rising-edge-trig */ +#define HD64465_PCCCSCIER_PSCE 0x10 /* status change enable */ +#define HD64465_PCCCSCIER_PCDE 0x08 /* card detect change enable */ +#define HD64465_PCCCSCIER_PRE 0x04 /* ready change enable */ +#define HD64465_PCCCSCIER_PBWE 0x02 /* battery warn change enable */ +#define HD64465_PCCCSCIER_PBDE 0x01 /* battery dead change enable*/ +#define HD64465_REG_PCC0SCR 0x12008 /* socket 0 software control */ +#define HD64465_PCCSCR_SHDN 0x10 /* TPS2206 SHutDowN pin */ +#define HD64465_PCCSCR_SWP 0x01 /* write protect */ +#define HD64465_REG_PCCPSR 0x1200A /* serial power switch control */ +#define HD64465_REG_PCC1ISR 0x12010 /* socket 1 interface status */ +#define HD64465_REG_PCC1GCR 0x12012 /* socket 1 general control */ +#define HD64465_REG_PCC1CSCR 0x12014 /* socket 1 card status change */ +#define HD64465_REG_PCC1CSCIER 0x12016 /* socket 1 card status change interrupt enable */ +#define HD64465_REG_PCC1SCR 0x12018 /* socket 1 software control */ + + +/* PS/2 Keyboard and mouse controller -- *not* register compatible */ +#define HD64465_REG_KBCSR 0x1dc00 /* Keyboard Control/Status reg */ +#define HD64465_KBCSR_KBCIE 0x8000 /* KBCK Input Enable */ +#define HD64465_KBCSR_KBCOE 0x4000 /* KBCK Output Enable */ +#define HD64465_KBCSR_KBDOE 0x2000 /* KB DATA Output Enable */ +#define HD64465_KBCSR_KBCD 0x1000 /* KBCK Driven */ +#define HD64465_KBCSR_KBDD 0x0800 /* KB DATA Driven */ +#define HD64465_KBCSR_KBCS 0x0400 /* KBCK pin Status */ +#define HD64465_KBCSR_KBDS 0x0200 /* KB DATA pin Status */ +#define HD64465_KBCSR_KBDP 0x0100 /* KB DATA Parity bit */ +#define HD64465_KBCSR_KBD_MASK 0x00ff /* KD DATA shift reg */ +#define HD64465_REG_KBISR 0x1dc04 /* Keyboard Interrupt Status reg */ +#define HD64465_KBISR_KBRDF 0x0001 /* KB Received Data Full */ +#define HD64465_REG_MSCSR 0x1dc10 /* Mouse Control/Status reg */ +#define HD64465_REG_MSISR 0x1dc14 /* Mouse Interrupt Status reg */ + + +/* + * Logical address at which the HD64465 is mapped. Note that this + * should always be in the P2 segment (uncached and untranslated). + */ +#ifndef CONFIG_HD64465_IOBASE +#define CONFIG_HD64465_IOBASE 0xb0000000 +#endif +/* + * The HD64465 multiplexes all its modules' interrupts onto + * this single interrupt. + */ +#ifndef CONFIG_HD64465_IRQ +#define CONFIG_HD64465_IRQ 5 +#endif + + +#define _HD64465_IO_MASK 0xf8000000 +#define is_hd64465_addr(addr) \ + ((addr & _HD64465_IO_MASK) == (CONFIG_HD64465_IOBASE & _HD64465_IO_MASK)) + +/* + * A range of 16 virtual interrupts generated by + * demuxing the HD64465 muxed interrupt. + */ +#define HD64465_IRQ_BASE OFFCHIP_IRQ_BASE +#define HD64465_IRQ_NUM 16 +#define HD64465_IRQ_ADC (HD64465_IRQ_BASE+0) +#define HD64465_IRQ_USB (HD64465_IRQ_BASE+1) +#define HD64465_IRQ_SCDI (HD64465_IRQ_BASE+2) +#define HD64465_IRQ_PARALLEL (HD64465_IRQ_BASE+3) +/* bit 4 is reserved */ +#define HD64465_IRQ_UART (HD64465_IRQ_BASE+5) +#define HD64465_IRQ_IRDA (HD64465_IRQ_BASE+6) +#define HD64465_IRQ_PS2MOUSE (HD64465_IRQ_BASE+7) +#define HD64465_IRQ_KBC (HD64465_IRQ_BASE+8) +#define HD64465_IRQ_TIMER1 (HD64465_IRQ_BASE+9) +#define HD64465_IRQ_TIMER0 (HD64465_IRQ_BASE+10) +#define HD64465_IRQ_GPIO (HD64465_IRQ_BASE+11) +#define HD64465_IRQ_AFE (HD64465_IRQ_BASE+12) +#define HD64465_IRQ_PCMCIA1 (HD64465_IRQ_BASE+13) +#define HD64465_IRQ_PCMCIA0 (HD64465_IRQ_BASE+14) +#define HD64465_IRQ_PS2KBD (HD64465_IRQ_BASE+15) + +/* Constants for PCMCIA mappings */ +#define HD64465_PCC_WINDOW 0x01000000 + +#define HD64465_PCC0_BASE 0xb8000000 /* area 6 */ +#define HD64465_PCC0_ATTR (HD64465_PCC0_BASE) +#define HD64465_PCC0_COMM (HD64465_PCC0_BASE+HD64465_PCC_WINDOW) +#define HD64465_PCC0_IO (HD64465_PCC0_BASE+2*HD64465_PCC_WINDOW) + +#define HD64465_PCC1_BASE 0xb4000000 /* area 5 */ +#define HD64465_PCC1_ATTR (HD64465_PCC1_BASE) +#define HD64465_PCC1_COMM (HD64465_PCC1_BASE+HD64465_PCC_WINDOW) +#define HD64465_PCC1_IO (HD64465_PCC1_BASE+2*HD64465_PCC_WINDOW) + +/* + * Base of USB controller interface (as memory) + */ +#define HD64465_USB_BASE (CONFIG_HD64465_IOBASE+0xb000) +#define HD64465_USB_LEN 0x1000 +/* + * Base of embedded SRAM, used for USB controller. + */ +#define HD64465_SRAM_BASE (CONFIG_HD64465_IOBASE+0x9000) +#define HD64465_SRAM_LEN 0x1000 + + + +#endif /* _ASM_SH_HD64465_ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/hd64465_gpio.h linux/include/asm-sh/hd64465_gpio.h --- v2.4.3/linux/include/asm-sh/hd64465_gpio.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/hd64465_gpio.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,47 @@ +#ifndef _ASM_SH_HD64465_GPIO_ +#define _ASM_SH_HD64465_GPIO_ 1 +/* + * $Id: hd64465_gpio.h,v 1.1 2001/01/02 15:35:22 mjd Exp $ + * + * Hitachi HD64465 companion chip: General Purpose IO pins support. + * This layer enables other device drivers to configure GPIO + * pins, get and set their values, and register an interrupt + * routine for when input pins change in hardware. + * + * by Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc. + */ +#include <linux/config.h> +#include <asm/hd64465.h> + +/* Macro to construct a portpin number (used in all + * subsequent functions) from a port letter and a pin + * number, e.g. HD64465_GPIO_PORTPIN('A', 5). + */ +#define HD64465_GPIO_PORTPIN(port,pin) (((port)-'A')<<3|(pin)) + +/* Pin configuration constants for _configure() */ +#define HD64465_GPIO_FUNCTION2 0 /* use the pin's *other* function */ +#define HD64465_GPIO_OUT 1 /* output */ +#define HD64465_GPIO_IN_PULLUP 2 /* input, pull-up MOS on */ +#define HD64465_GPIO_IN 3 /* input */ + +/* Configure a pin's direction */ +extern void hd64465_gpio_configure(int portpin, int direction); + +/* Get, set value */ +extern void hd64465_gpio_set_pin(int portpin, unsigned int value); +extern unsigned int hd64465_gpio_get_pin(int portpin); +extern void hd64465_gpio_set_port(int port, unsigned int value); +extern unsigned int hd64465_gpio_get_port(int port); + +/* mode constants for _register_irq() */ +#define HD64465_GPIO_FALLING 0 +#define HD64465_GPIO_RISING 1 + +/* Interrupt on external value change */ +extern void hd64465_gpio_register_irq(int portpin, int mode, + void (*handler)(int portpin, void *dev), void *dev); +extern void hd64465_gpio_unregister_irq(int portpin); + +#endif /* _ASM_SH_HD64465_GPIO_ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h --- v2.4.3/linux/include/asm-sh/ide.h Mon Oct 2 11:57:34 2000 +++ linux/include/asm-sh/ide.h Wed Apr 11 21:24:52 2001 @@ -28,7 +28,7 @@ { switch (base) { case 0x01f0: return 77; - case 0x0170: return 77; + case 0x0170: return 78; default: return 0; } diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io.h linux/include/asm-sh/io.h --- v2.4.3/linux/include/asm-sh/io.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/io.h Wed Apr 11 21:24:52 2001 @@ -35,7 +35,7 @@ */ #ifdef __KERNEL__ -#ifdef CONFIG_SH_GENERIC +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_CQREEK) || defined(CONFIG_SH_UNKNOWN) /* In a generic kernel, we always go through the machine vector. */ @@ -70,7 +70,6 @@ # define __writel(v,a) sh_mv.mv_writel((v),(a)) # define __ioremap(a,s) sh_mv.mv_ioremap((a), (s)) -# define __ioremap_nocache(a,s) sh_mv.mv_ioremap_nocache((a), (s)) # define __iounmap(a) sh_mv.mv_iounmap((a)) # define __isa_port2addr(a) sh_mv.mv_isa_port2addr(a) @@ -110,10 +109,20 @@ # if defined(CONFIG_SH_HP600) # include <asm/io_hd64461.h> -# elif defined(CONFIG_SH_OVERDRIVE) +# elif defined(CONFIG_SH_7750_OVERDRIVE) # include <asm/io_od.h> # elif defined(CONFIG_SH_SOLUTION_ENGINE) # include <asm/io_se.h> +# elif defined(CONFIG_SH_DMIDA) || \ + defined(CONFIG_SH_STB1_HARP) || \ + defined(CONFIG_SH_STB1_OVERDRIVE) +# include <asm/io_hd64465.h> +# elif defined(CONFIG_SH_EC3104) +# include <asm/io_ec3104.h> +# elif defined(CONFIG_SH_DREAMCAST) +# include <asm/io_dc.h> +# elif defined(CONFIG_SH_CAT68701) +# include <asm/io_cat68701.h> # elif defined(CONFIG_SH_UNKNOWN) # include <asm/io_unknown.h> # else @@ -126,40 +135,38 @@ #endif /* __KERNEL__ */ /* These are always function calls, in both kernel and user space */ -extern unsigned int _inb (unsigned long port); -extern unsigned int _inw (unsigned long port); +extern unsigned char _inb (unsigned long port); +extern unsigned short _inw (unsigned long port); extern unsigned int _inl (unsigned long port); -extern void _outb (unsigned char b,unsigned long port); -extern void _outw (unsigned short w,unsigned long port); -extern void _outl (unsigned int l,unsigned long port); -extern unsigned int _inb_p (unsigned long port); -extern unsigned int _inw_p (unsigned long port); +extern void _outb (unsigned char b, unsigned long port); +extern void _outw (unsigned short w, unsigned long port); +extern void _outl (unsigned int l, unsigned long port); +extern unsigned char _inb_p (unsigned long port); +extern unsigned short _inw_p (unsigned long port); extern unsigned int _inl_p (unsigned long port); -extern void _outb_p (unsigned char b,unsigned long port); -extern void _outw_p (unsigned short w,unsigned long port); -extern void _outl_p (unsigned int l,unsigned long port); +extern void _outb_p (unsigned char b, unsigned long port); +extern void _outw_p (unsigned short w, unsigned long port); +extern void _outl_p (unsigned int l, unsigned long port); extern void _insb (unsigned long port, void *dst, unsigned long count); extern void _insw (unsigned long port, void *dst, unsigned long count); extern void _insl (unsigned long port, void *dst, unsigned long count); extern void _outsb (unsigned long port, const void *src, unsigned long count); extern void _outsw (unsigned long port, const void *src, unsigned long count); extern void _outsl (unsigned long port, const void *src, unsigned long count); -extern unsigned long _readb(unsigned long addr); -extern unsigned long _readw(unsigned long addr); -extern unsigned long _readl(unsigned long addr); +extern unsigned char _readb(unsigned long addr); +extern unsigned short _readw(unsigned long addr); +extern unsigned int _readl(unsigned long addr); extern void _writeb(unsigned char b, unsigned long addr); extern void _writew(unsigned short b, unsigned long addr); extern void _writel(unsigned int b, unsigned long addr); #ifdef __KERNEL__ -extern unsigned long ___raw_readb(unsigned long addr); -extern unsigned long ___raw_readw(unsigned long addr); -extern unsigned long ___raw_readl(unsigned long addr); -extern unsigned long ___raw_readq(unsigned long addr); +extern unsigned char ___raw_readb(unsigned long addr); +extern unsigned short ___raw_readw(unsigned long addr); +extern unsigned int ___raw_readl(unsigned long addr); extern void ___raw_writeb(unsigned char b, unsigned long addr); extern void ___raw_writew(unsigned short b, unsigned long addr); extern void ___raw_writel(unsigned int b, unsigned long addr); -extern void ___raw_writeq(unsigned long b, unsigned long addr); #endif #ifdef __KERNEL__ @@ -291,20 +298,20 @@ /* Userspace declarations. */ -extern unsigned int inb(unsigned long port); -extern unsigned int inw(unsigned long port); +extern unsigned char inb(unsigned long port); +extern unsigned short inw(unsigned long port); extern unsigned int inl(unsigned long port); -extern void outb(unsigned char b,unsigned long port); -extern void outw(unsigned short w,unsigned long port); -extern void outl(unsigned int l,unsigned long port); -extern void insb (unsigned long port, void *dst, unsigned long count); -extern void insw (unsigned long port, void *dst, unsigned long count); -extern void insl (unsigned long port, void *dst, unsigned long count); -extern void outsb (unsigned long port, const void *src, unsigned long count); -extern void outsw (unsigned long port, const void *src, unsigned long count); -extern void outsl (unsigned long port, const void *src, unsigned long count); -extern unsigned long readb(unsigned long addr); -extern unsigned long readw(unsigned long addr); +extern void outb(unsigned char b, unsigned long port); +extern void outw(unsigned short w, unsigned long port); +extern void outl(unsigned int l, unsigned long port); +extern void insb(unsigned long port, void *dst, unsigned long count); +extern void insw(unsigned long port, void *dst, unsigned long count); +extern void insl(unsigned long port, void *dst, unsigned long count); +extern void outsb(unsigned long port, const void *src, unsigned long count); +extern void outsw(unsigned long port, const void *src, unsigned long count); +extern void outsl(unsigned long port, const void *src, unsigned long count); +extern unsigned char readb(unsigned long addr); +extern unsigned short readw(unsigned long addr); extern unsigned long readl(unsigned long addr); extern void writeb(unsigned char b, unsigned long addr); extern void writew(unsigned short b, unsigned long addr); @@ -342,17 +349,17 @@ extern void memset_io(unsigned long, int, unsigned long); /* SuperH on-chip I/O functions */ -extern __inline__ unsigned long ctrl_inb(unsigned long addr) +extern __inline__ unsigned char ctrl_inb(unsigned long addr) { return *(volatile unsigned char*)addr; } -extern __inline__ unsigned long ctrl_inw(unsigned long addr) +extern __inline__ unsigned short ctrl_inw(unsigned long addr) { return *(volatile unsigned short*)addr; } -extern __inline__ unsigned long ctrl_inl(unsigned long addr) +extern __inline__ unsigned int ctrl_inl(unsigned long addr) { return *(volatile unsigned long*)addr; } @@ -412,20 +419,12 @@ return __ioremap(offset, size); } -/* - * This one maps high address device memory and turns off caching for that area. - * it's useful if some control registers are in such an area and write combining - * or read caching is not desirable: - */ -static __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size) -{ - return __ioremap_nocache(offset, size); -} - static __inline__ void iounmap(void *addr) { return __iounmap(addr); } + +#define ioremap_nocache(off,size) ioremap(off,size) static __inline__ int check_signature(unsigned long io_addr, const unsigned char *signature, int length) diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_cat68701.h linux/include/asm-sh/io_cat68701.h --- v2.4.3/linux/include/asm-sh/io_cat68701.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/io_cat68701.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,89 @@ +/* + * include/asm-sh/io_cat68701.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * 2001 Yutarou Ebihar (ebihara@si-linux.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an AONE Corp. CAT-68701 SH7708 Borad + */ + +#ifndef _ASM_SH_IO_CAT68701_H +#define _ASM_SH_IO_CAT68701_H + +#include <asm/io_generic.h> + +extern unsigned char cat68701_inb(unsigned long port); +extern unsigned short cat68701_inw(unsigned long port); +extern unsigned int cat68701_inl(unsigned long port); + +extern void cat68701_outb(unsigned char value, unsigned long port); +extern void cat68701_outw(unsigned short value, unsigned long port); +extern void cat68701_outl(unsigned int value, unsigned long port); + +extern unsigned char cat68701_inb_p(unsigned long port); +extern void cat68701_outb_p(unsigned char value, unsigned long port); + +extern void cat68701_insb(unsigned long port, void *addr, unsigned long count); +extern void cat68701_insw(unsigned long port, void *addr, unsigned long count); +extern void cat68701_insl(unsigned long port, void *addr, unsigned long count); +extern void cat68701_outsb(unsigned long port, const void *addr, unsigned long count); +extern void cat68701_outsw(unsigned long port, const void *addr, unsigned long count); +extern void cat68701_outsl(unsigned long port, const void *addr, unsigned long count); + +extern unsigned char cat68701_readb(unsigned long addr); +extern unsigned short cat68701_readw(unsigned long addr); +extern unsigned int cat68701_readl(unsigned long addr); +extern void cat68701_writeb(unsigned char b, unsigned long addr); +extern void cat68701_writew(unsigned short b, unsigned long addr); +extern void cat68701_writel(unsigned int b, unsigned long addr); + +extern void * cat68701_ioremap(unsigned long offset, unsigned long size); +extern void cat68701_iounmap(void *addr); + +extern unsigned long cat68701_isa_port2addr(unsigned long offset); +extern int cat68701_irq_demux(int irq); + +extern void setup_cat68701(void); +extern void init_cat68701_IRQ(void); +extern void heartbeat_cat68701(void); + +#ifdef __WANT_IO_DEF + +# define __inb cat68701_inb +# define __inw cat68701_inw +# define __inl cat68701_inl +# define __outb cat68701_outb +# define __outw cat68701_outw +# define __outl cat68701_outl + +# define __inb_p cat68701_inb_p +# define __inw_p cat68701_inw +# define __inl_p cat68701_inl +# define __outb_p cat68701_outb_p +# define __outw_p cat68701_outw +# define __outl_p cat68701_outl + +# define __insb cat68701_insb +# define __insw cat68701_insw +# define __insl cat68701_insl +# define __outsb cat68701_outsb +# define __outsw cat68701_outsw +# define __outsl cat68701_outsl + +# define __readb cat68701_readb +# define __readw cat68701_readw +# define __readl cat68701_readl +# define __writeb cat68701_writeb +# define __writew cat68701_writew +# define __writel cat68701_writel + +# define __isa_port2addr cat68701_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_CAT68701_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_dc.h linux/include/asm-sh/io_dc.h --- v2.4.3/linux/include/asm-sh/io_dc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/io_dc.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,49 @@ +/* + * $Id: io_dc.h,v 1.1 2001/04/01 15:02:56 yaegashi Exp $ + * IO functions for SEGA Dreamcast + */ + +#ifndef _ASM_SH_IO_DREAMCAST_H +#define _ASM_SH_IO_DREAMCAST_H + +#include <asm/io_generic.h> + +unsigned long dreamcast_isa_port2addr(unsigned long offset); + +#ifdef __WANT_IO_DEF + +# define __inb generic_inb +# define __inw generic_inw +# define __inl generic_inl +# define __outb generic_outb +# define __outw generic_outw +# define __outl generic_outl + +# define __inb_p generic_inb_p +# define __inw_p generic_inw +# define __inl_p generic_inl +# define __outb_p generic_outb_p +# define __outw_p generic_outw +# define __outl_p generic_outl + +# define __insb generic_insb +# define __insw generic_insw +# define __insl generic_insl +# define __outsb generic_outsb +# define __outsw generic_outsw +# define __outsl generic_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr dreamcast_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_DREAMCAST_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_ec3104.h linux/include/asm-sh/io_ec3104.h --- v2.4.3/linux/include/asm-sh/io_ec3104.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/io_ec3104.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,54 @@ +#ifndef _ASM_SH_IO_EC3104_H +#define _ASM_SH_IO_EC3104_H + +#include <asm/io_generic.h> +#include <linux/types.h> + +extern unsigned char ec3104_inb(unsigned long port); +extern unsigned short ec3104_inw(unsigned long port); +extern unsigned long ec3104_inl(unsigned long port); + +extern void ec3104_outb(unsigned char value, unsigned long port); +extern void ec3104_outw(unsigned short value, unsigned long port); +extern void ec3104_outl(unsigned long value, unsigned long port); + +extern int ec3104_irq_demux(int irq); + +#ifdef __WANT_IO_DEF + +# define __inb ec3104_inb +# define __inw ec3104_inw +# define __inl ec3104_inl +# define __outb ec3104_outb +# define __outw ec3104_outw +# define __outl ec3104_outl + +# define __inb_p ec3104_inb +# define __inw_p ec3104_inw +# define __inl_p ec3104_inl +# define __outb_p ec3104_outb +# define __outw_p ec3104_outw +# define __outl_p ec3104_outl + +# define __insb generic_insb +# define __insw generic_insw +# define __insl generic_insl +# define __outsb generic_outsb +# define __outsw generic_outsw +# define __outsl generic_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr generic_isa_port2addr +# define __ioremap generic_ioremap +# define __ioremap_nocache generic_ioremap_nocache +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_EC3104_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_generic.h linux/include/asm-sh/io_generic.h --- v2.4.3/linux/include/asm-sh/io_generic.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/io_generic.h Wed Apr 11 21:24:52 2001 @@ -14,37 +14,36 @@ extern unsigned long generic_io_base; -extern unsigned long generic_inb(unsigned int port); -extern unsigned long generic_inw(unsigned int port); -extern unsigned long generic_inl(unsigned int port); +extern unsigned char generic_inb(unsigned long port); +extern unsigned short generic_inw(unsigned long port); +extern unsigned int generic_inl(unsigned long port); -extern void generic_outb(unsigned long value, unsigned int port); -extern void generic_outw(unsigned long value, unsigned int port); -extern void generic_outl(unsigned long value, unsigned int port); +extern void generic_outb(unsigned char value, unsigned long port); +extern void generic_outw(unsigned short value, unsigned long port); +extern void generic_outl(unsigned int value, unsigned long port); -extern unsigned long generic_inb_p(unsigned int port); -extern unsigned long generic_inw_p(unsigned int port); -extern unsigned long generic_inl_p(unsigned int port); -extern void generic_outb_p(unsigned long value, unsigned int port); -extern void generic_outw_p(unsigned long value, unsigned int port); -extern void generic_outl_p(unsigned long value, unsigned int port); +extern unsigned char generic_inb_p(unsigned long port); +extern unsigned short generic_inw_p(unsigned long port); +extern unsigned int generic_inl_p(unsigned long port); +extern void generic_outb_p(unsigned char value, unsigned long port); +extern void generic_outw_p(unsigned short value, unsigned long port); +extern void generic_outl_p(unsigned int value, unsigned long port); -extern void generic_insb(unsigned int port, void *addr, unsigned long count); -extern void generic_insw(unsigned int port, void *addr, unsigned long count); -extern void generic_insl(unsigned int port, void *addr, unsigned long count); -extern void generic_outsb(unsigned int port, const void *addr, unsigned long count); -extern void generic_outsw(unsigned int port, const void *addr, unsigned long count); -extern void generic_outsl(unsigned int port, const void *addr, unsigned long count); +extern void generic_insb(unsigned long port, void *addr, unsigned long count); +extern void generic_insw(unsigned long port, void *addr, unsigned long count); +extern void generic_insl(unsigned long port, void *addr, unsigned long count); +extern void generic_outsb(unsigned long port, const void *addr, unsigned long count); +extern void generic_outsw(unsigned long port, const void *addr, unsigned long count); +extern void generic_outsl(unsigned long port, const void *addr, unsigned long count); -extern unsigned long generic_readb(unsigned long addr); -extern unsigned long generic_readw(unsigned long addr); -extern unsigned long generic_readl(unsigned long addr); +extern unsigned char generic_readb(unsigned long addr); +extern unsigned short generic_readw(unsigned long addr); +extern unsigned int generic_readl(unsigned long addr); extern void generic_writeb(unsigned char b, unsigned long addr); extern void generic_writew(unsigned short b, unsigned long addr); extern void generic_writel(unsigned int b, unsigned long addr); extern void *generic_ioremap(unsigned long offset, unsigned long size); -extern void *generic_ioremap_nocache (unsigned long offset, unsigned long size); extern void generic_iounmap(void *addr); extern unsigned long generic_isa_port2addr(unsigned long offset); diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_hd64461.h linux/include/asm-sh/io_hd64461.h --- v2.4.3/linux/include/asm-sh/io_hd64461.h Mon Oct 2 11:57:34 2000 +++ linux/include/asm-sh/io_hd64461.h Wed Apr 11 21:24:52 2001 @@ -14,23 +14,24 @@ #include <asm/io_generic.h> -extern unsigned long hd64461_inb(unsigned int port); -extern unsigned long hd64461_inw(unsigned int port); -extern unsigned long hd64461_inl(unsigned int port); - -extern void hd64461_outb(unsigned long value, unsigned int port); -extern void hd64461_outw(unsigned long value, unsigned int port); -extern void hd64461_outl(unsigned long value, unsigned int port); - -extern unsigned long hd64461_inb_p(unsigned int port); -extern void hd64461_outb_p(unsigned long value, unsigned int port); - -extern void hd64461_insb(unsigned int port, void *addr, unsigned long count); -extern void hd64461_insw(unsigned int port, void *addr, unsigned long count); -extern void hd64461_insl(unsigned int port, void *addr, unsigned long count); -extern void hd64461_outsb(unsigned int port, const void *addr, unsigned long count); -extern void hd64461_outsw(unsigned int port, const void *addr, unsigned long count); -extern void hd64461_outsl(unsigned int port, const void *addr, unsigned long count); +extern unsigned char hd64461_inb(unsigned long port); +extern unsigned short hd64461_inw(unsigned long port); +extern unsigned int hd64461_inl(unsigned long port); + +extern void hd64461_outb(unsigned char value, unsigned long port); +extern void hd64461_outw(unsigned short value, unsigned long port); +extern void hd64461_outl(unsigned int value, unsigned long port); + +extern unsigned char hd64461_inb_p(unsigned long port); +extern void hd64461_outb_p(unsigned char value, unsigned long port); + +extern void hd64461_insb(unsigned long port, void *addr, unsigned long count); +extern void hd64461_insw(unsigned long port, void *addr, unsigned long count); +extern void hd64461_insl(unsigned long port, void *addr, unsigned long count); +extern void hd64461_outsb(unsigned long port, const void *addr, unsigned long count); +extern void hd64461_outsw(unsigned long port, const void *addr, unsigned long count); +extern void hd64461_outsl(unsigned long port, const void *addr, unsigned long count); +extern int hd64461_irq_demux(int irq); #ifdef __WANT_IO_DEF @@ -64,6 +65,7 @@ # define __isa_port2addr generic_isa_port2addr # define __ioremap generic_ioremap +# define __ioremap_nocache generic_ioremap_nocache # define __iounmap generic_iounmap #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_hd64465.h linux/include/asm-sh/io_hd64465.h --- v2.4.3/linux/include/asm-sh/io_hd64465.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/io_hd64465.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,90 @@ +/* + * include/asm-sh/io_hd64465.h + * + * By Greg Banks <gbanks@pocketpenguins.com> + * (c) 2000 PocketPenguins Inc. + * + * Derived from io_hd64461.h, which bore the message: + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an HD64465 "Windows CE Intelligent Peripheral Controller". + */ + +#ifndef _ASM_SH_IO_HD64465_H +#define _ASM_SH_IO_HD64465_H + +#include <asm/io_generic.h> + +extern unsigned char hd64465_inb(unsigned long port); +extern unsigned short hd64465_inw(unsigned long port); +extern unsigned int hd64465_inl(unsigned long port); + +extern void hd64465_outb(unsigned char value, unsigned long port); +extern void hd64465_outw(unsigned short value, unsigned long port); +extern void hd64465_outl(unsigned int value, unsigned long port); + +extern unsigned char hd64465_inb_p(unsigned long port); +extern void hd64465_outb_p(unsigned char value, unsigned long port); + +extern void hd64465_insb(unsigned long port, void *addr, unsigned long count); +extern void hd64465_insw(unsigned long port, void *addr, unsigned long count); +extern void hd64465_insl(unsigned long port, void *addr, unsigned long count); +extern void hd64465_outsb(unsigned long port, const void *addr, unsigned long count); +extern void hd64465_outsw(unsigned long port, const void *addr, unsigned long count); +extern void hd64465_outsl(unsigned long port, const void *addr, unsigned long count); +extern unsigned long hd64465_isa_port2addr(unsigned long offset); +extern int hd64465_irq_demux(int irq); +/* Provision for generic secondary demux step -- used by PCMCIA code */ +extern void hd64465_register_irq_demux(int irq, + int (*demux)(int irq, void *dev), void *dev); +extern void hd64465_unregister_irq_demux(int irq); +/* Set this variable to 1 to see port traffic */ +extern int hd64465_io_debug; +/* Map a range of ports to a range of kernel virtual memory. + */ +extern void hd64465_port_map(unsigned short baseport, unsigned int nports, + unsigned long addr, unsigned char shift); +extern void hd64465_port_unmap(unsigned short baseport, unsigned int nports); + + +#ifdef __WANT_IO_DEF + +# define __inb hd64465_inb +# define __inw hd64465_inw +# define __inl hd64465_inl +# define __outb hd64465_outb +# define __outw hd64465_outw +# define __outl hd64465_outl + +# define __inb_p hd64465_inb_p +# define __inw_p hd64465_inw +# define __inl_p hd64465_inl +# define __outb_p hd64465_outb_p +# define __outw_p hd64465_outw +# define __outl_p hd64465_outl + +# define __insb hd64465_insb +# define __insw hd64465_insw +# define __insl hd64465_insl +# define __outsb hd64465_outsb +# define __outsw hd64465_outsw +# define __outsl hd64465_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr hd64465_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + + +#endif + +#endif /* _ASM_SH_IO_HD64465_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_od.h linux/include/asm-sh/io_od.h --- v2.4.3/linux/include/asm-sh/io_od.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/io_od.h Wed Apr 11 21:24:52 2001 @@ -14,27 +14,27 @@ #include <asm/io_generic.h> -extern unsigned long od_inb(unsigned int port); -extern unsigned long od_inw(unsigned int port); -extern unsigned long od_inl(unsigned int port); - -extern void od_outb(unsigned long value, unsigned int port); -extern void od_outw(unsigned long value, unsigned int port); -extern void od_outl(unsigned long value, unsigned int port); - -extern unsigned long od_inb_p(unsigned int port); -extern unsigned long od_inw_p(unsigned int port); -extern unsigned long od_inl_p(unsigned int port); -extern void od_outb_p(unsigned long value, unsigned int port); -extern void od_outw_p(unsigned long value, unsigned int port); -extern void od_outl_p(unsigned long value, unsigned int port); - -extern void od_insb(unsigned int port, void *addr, unsigned long count); -extern void od_insw(unsigned int port, void *addr, unsigned long count); -extern void od_insl(unsigned int port, void *addr, unsigned long count); -extern void od_outsb(unsigned int port, const void *addr, unsigned long count); -extern void od_outsw(unsigned int port, const void *addr, unsigned long count); -extern void od_outsl(unsigned int port, const void *addr, unsigned long count); +extern unsigned char od_inb(unsigned long port); +extern unsigned short od_inw(unsigned long port); +extern unsigned int od_inl(unsigned long port); + +extern void od_outb(unsigned char value, unsigned long port); +extern void od_outw(unsigned short value, unsigned long port); +extern void od_outl(unsigned int value, unsigned long port); + +extern unsigned char od_inb_p(unsigned long port); +extern unsigned short od_inw_p(unsigned long port); +extern unsigned int od_inl_p(unsigned long port); +extern void od_outb_p(unsigned char value, unsigned long port); +extern void od_outw_p(unsigned short value, unsigned long port); +extern void od_outl_p(unsigned int value, unsigned long port); + +extern void od_insb(unsigned long port, void *addr, unsigned long count); +extern void od_insw(unsigned long port, void *addr, unsigned long count); +extern void od_insl(unsigned long port, void *addr, unsigned long count); +extern void od_outsb(unsigned long port, const void *addr, unsigned long count); +extern void od_outsw(unsigned long port, const void *addr, unsigned long count); +extern void od_outsl(unsigned long port, const void *addr, unsigned long count); extern unsigned long od_isa_port2addr(unsigned long offset); @@ -70,7 +70,6 @@ # define __isa_port2addr od_isa_port2addr # define __ioremap generic_ioremap -# define __ioremap_nocache generic_ioremap_nocache # define __iounmap generic_iounmap #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_se.h linux/include/asm-sh/io_se.h --- v2.4.3/linux/include/asm-sh/io_se.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/io_se.h Wed Apr 11 21:24:52 2001 @@ -14,27 +14,27 @@ #include <asm/io_generic.h> -extern unsigned long se_inb(unsigned int port); -extern unsigned long se_inw(unsigned int port); -extern unsigned long se_inl(unsigned int port); - -extern void se_outb(unsigned long value, unsigned int port); -extern void se_outw(unsigned long value, unsigned int port); -extern void se_outl(unsigned long value, unsigned int port); - -extern unsigned long se_inb_p(unsigned int port); -extern void se_outb_p(unsigned long value, unsigned int port); - -extern void se_insb(unsigned int port, void *addr, unsigned long count); -extern void se_insw(unsigned int port, void *addr, unsigned long count); -extern void se_insl(unsigned int port, void *addr, unsigned long count); -extern void se_outsb(unsigned int port, const void *addr, unsigned long count); -extern void se_outsw(unsigned int port, const void *addr, unsigned long count); -extern void se_outsl(unsigned int port, const void *addr, unsigned long count); - -extern unsigned long se_readb(unsigned long addr); -extern unsigned long se_readw(unsigned long addr); -extern unsigned long se_readl(unsigned long addr); +extern unsigned char se_inb(unsigned long port); +extern unsigned short se_inw(unsigned long port); +extern unsigned int se_inl(unsigned long port); + +extern void se_outb(unsigned char value, unsigned long port); +extern void se_outw(unsigned short value, unsigned long port); +extern void se_outl(unsigned int value, unsigned long port); + +extern unsigned char se_inb_p(unsigned long port); +extern void se_outb_p(unsigned char value, unsigned long port); + +extern void se_insb(unsigned long port, void *addr, unsigned long count); +extern void se_insw(unsigned long port, void *addr, unsigned long count); +extern void se_insl(unsigned long port, void *addr, unsigned long count); +extern void se_outsb(unsigned long port, const void *addr, unsigned long count); +extern void se_outsw(unsigned long port, const void *addr, unsigned long count); +extern void se_outsl(unsigned long port, const void *addr, unsigned long count); + +extern unsigned char se_readb(unsigned long addr); +extern unsigned short se_readw(unsigned long addr); +extern unsigned int se_readl(unsigned long addr); extern void se_writeb(unsigned char b, unsigned long addr); extern void se_writew(unsigned short b, unsigned long addr); extern void se_writel(unsigned int b, unsigned long addr); @@ -73,7 +73,6 @@ # define __isa_port2addr se_isa_port2addr # define __ioremap generic_ioremap -# define __ioremap_nocache generic_ioremap_nocache # define __iounmap generic_iounmap #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/io_unknown.h linux/include/asm-sh/io_unknown.h --- v2.4.3/linux/include/asm-sh/io_unknown.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/io_unknown.h Wed Apr 11 21:24:52 2001 @@ -12,38 +12,37 @@ #ifndef _ASM_SH_IO_UNKNOWN_H #define _ASM_SH_IO_UNKNOWN_H -extern unsigned long unknown_inb(unsigned int port); -extern unsigned long unknown_inw(unsigned int port); -extern unsigned long unknown_inl(unsigned int port); - -extern void unknown_outb(unsigned long value, unsigned int port); -extern void unknown_outw(unsigned long value, unsigned int port); -extern void unknown_outl(unsigned long value, unsigned int port); - -extern unsigned long unknown_inb_p(unsigned int port); -extern unsigned long unknown_inw_p(unsigned int port); -extern unsigned long unknown_inl_p(unsigned int port); -extern void unknown_outb_p(unsigned long value, unsigned int port); -extern void unknown_outw_p(unsigned long value, unsigned int port); -extern void unknown_outl_p(unsigned long value, unsigned int port); - -extern void unknown_insb(unsigned int port, void *addr, unsigned long count); -extern void unknown_insw(unsigned int port, void *addr, unsigned long count); -extern void unknown_insl(unsigned int port, void *addr, unsigned long count); -extern void unknown_outsb(unsigned int port, const void *addr, unsigned long count); -extern void unknown_outsw(unsigned int port, const void *addr, unsigned long count); -extern void unknown_outsl(unsigned int port, const void *addr, unsigned long count); - -extern unsigned long unknown_readb(unsigned long addr); -extern unsigned long unknown_readw(unsigned long addr); -extern unsigned long unknown_readl(unsigned long addr); +extern unsigned char unknown_inb(unsigned long port); +extern unsigned short unknown_inw(unsigned long port); +extern unsigned int unknown_inl(unsigned long port); + +extern void unknown_outb(unsigned char value, unsigned long port); +extern void unknown_outw(unsigned short value, unsigned long port); +extern void unknown_outl(unsigned int value, unsigned long port); + +extern unsigned char unknown_inb_p(unsigned long port); +extern unsigned short unknown_inw_p(unsigned long port); +extern unsigned int unknown_inl_p(unsigned long port); +extern void unknown_outb_p(unsigned char value, unsigned long port); +extern void unknown_outw_p(unsigned short value, unsigned long port); +extern void unknown_outl_p(unsigned int value, unsigned long port); + +extern void unknown_insb(unsigned long port, void *addr, unsigned long count); +extern void unknown_insw(unsigned long port, void *addr, unsigned long count); +extern void unknown_insl(unsigned long port, void *addr, unsigned long count); +extern void unknown_outsb(unsigned long port, const void *addr, unsigned long count); +extern void unknown_outsw(unsigned long port, const void *addr, unsigned long count); +extern void unknown_outsl(unsigned long port, const void *addr, unsigned long count); + +extern unsigned char unknown_readb(unsigned long addr); +extern unsigned short unknown_readw(unsigned long addr); +extern unsigned int unknown_readl(unsigned long addr); extern void unknown_writeb(unsigned char b, unsigned long addr); extern void unknown_writew(unsigned short b, unsigned long addr); extern void unknown_writel(unsigned int b, unsigned long addr); extern unsigned long unknown_isa_port2addr(unsigned long offset); -extern void * unknown_ioremap(unsigned long offset, unsigned long size); -extern void * unknown_ioremap_nocache (unsigned long offset, unsigned long size); +extern void *unknown_ioremap(unsigned long offset, unsigned long size); extern void unknown_iounmap(void *addr); #ifdef __WANT_IO_DEF @@ -78,7 +77,6 @@ # define __isa_port2addr unknown_isa_port2addr # define __ioremap unknown_ioremap -# define __ioremap_nocache unknown_ioremap_nocache # define __iounmap unknown_iounmap #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/irq.h linux/include/asm-sh/irq.h --- v2.4.3/linux/include/asm-sh/irq.h Mon Oct 2 11:57:34 2000 +++ linux/include/asm-sh/irq.h Wed Apr 11 21:24:52 2001 @@ -12,6 +12,7 @@ #include <linux/config.h> #include <asm/machvec.h> +#include <asm/ptrace.h> /* for pt_regs */ #if defined(__sh3__) #define INTC_IPRA 0xfffffee2UL @@ -32,12 +33,24 @@ #define RTC_IPR_POS 0 #define RTC_PRIORITY TIMER_PRIORITY +#define DMTE0_IRQ 34 +#define DMTE1_IRQ 35 +#define DMTE2_IRQ 36 +#define DMTE3_IRQ 37 +#define DMAE_IRQ 38 +#define DMA_IPR_ADDR INTC_IPRC +#define DMA_IPR_POS 2 +#define DMA_PRIORITY 7 + +#if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \ + defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) #define SCI_ERI_IRQ 23 #define SCI_RXI_IRQ 24 #define SCI_TXI_IRQ 25 #define SCI_IPR_ADDR INTC_IPRB #define SCI_IPR_POS 1 #define SCI_PRIORITY 3 +#endif #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) #define SCIF_ERI_IRQ 56 @@ -55,7 +68,7 @@ #define IRDA_IPR_ADDR INTC_IPRE #define IRDA_IPR_POS 2 #define IRDA_PRIORITY 3 -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) #define SCIF_ERI_IRQ 40 #define SCIF_RXI_IRQ 41 #define SCIF_BRI_IRQ 42 @@ -63,38 +76,87 @@ #define SCIF_IPR_ADDR INTC_IPRC #define SCIF_IPR_POS 1 #define SCIF_PRIORITY 3 +#if defined(CONFIG_CPU_SUBTYPE_ST40STB1) +#define SCIF1_ERI_IRQ 23 +#define SCIF1_RXI_IRQ 24 +#define SCIF1_BRI_IRQ 25 +#define SCIF1_TXI_IRQ 26 +#define SCIF1_IPR_ADDR INTC_IPRB +#define SCIF1_IPR_POS 1 +#define SCIF1_PRIORITY 3 +#endif #endif -#ifdef CONFIG_SH_GENERIC -/* In a generic kernel, NR_IRQS is an upper bound, and we should use - * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value. +/* NR_IRQS is made from three components: + * 1. ONCHIP_NR_IRQS - number of IRLS + on-chip peripherial modules + * 2. PINT_NR_IRQS - number of PINT interrupts + * 3. OFFCHIP_NR_IRQS - numbe of IRQs from off-chip peripherial modules */ -#define NR_IRQS 80 -#define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs) + +/* 1. ONCHIP_NR_IRQS */ +#ifdef CONFIG_SH_GENERIC +# define ONCHIP_NR_IRQS 89 #else -#if defined(__SH4__) -/* - * 48 = 32+16 - * - * 32 for on chip support modules. - * 16 for external interrupts. - * - */ -#define NR_IRQS 48 -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) -#define NR_IRQS 64 -#elif defined(CONFIG_CPU_SUBTYPE_SH7708) -#define NR_IRQS 32 -#elif defined(CONFIG_CPU_SUBTYPE_SH7709) -#ifdef CONFIG_HD64461 -#define NR_IRQS 80 /* HD64461_IRQBASE+16, see hd64461.h */ +# if defined(CONFIG_CPU_SUBTYPE_SH7707) +# define ONCHIP_NR_IRQS 64 +# define PINT_NR_IRQS 16 +# elif defined(CONFIG_CPU_SUBTYPE_SH7708) +# define ONCHIP_NR_IRQS 32 +# elif defined(CONFIG_CPU_SUBTYPE_SH7709) +# define ONCHIP_NR_IRQS 64 // Actually 61 +# define PINT_NR_IRQS 16 +# elif defined(CONFIG_CPU_SUBTYPE_SH7750) +# define ONCHIP_NR_IRQS 48 // Actually 44 +# elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) +# define ONCHIP_NR_IRQS 89 +# endif +#endif + +/* 2. PINT_NR_IRQS */ +#ifdef CONFIG_SH_GENERIC +# define PINT_NR_IRQS 16 #else -#define NR_IRQS 61 +# ifndef PINT_NR_IRQS +# define PINT_NR_IRQS 0 +# endif #endif + +#if PINT_NR_IRQS > 0 +# define PINT_IRQ_BASE ONCHIP_NR_IRQS #endif -#define ACTUAL_NR_IRQS NR_IRQS + +/* 3. OFFCHIP_NR_IRQS */ +#ifdef CONFIG_SH_GENERIC +# define OFFCHIP_NR_IRQS 16 +#else +# if defined(CONFIG_HD64461) +# define OFFCHIP_NR_IRQS 16 +# elif defined(CONFIG_HD64465) +# define OFFCHIP_NR_IRQS 16 +# elif defined (CONFIG_SH_EC3104) +# define OFFCHIP_NR_IRQS 16 +# else +# define OFFCHIP_NR_IRQS 0 +# endif #endif +#if OFFCHIP_NR_IRQS > 0 +# define OFFCHIP_IRQ_BASE (ONCHIP_NR_IRQS + PINT_NR_IRQS) +#endif + +/* NR_IRQS. 1+2+3 */ +#define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS) + +/* In a generic kernel, NR_IRQS is an upper bound, and we should use + * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value. + */ +#ifdef CONFIG_SH_GENERIC +# define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs) +#else +# define ACTUAL_NR_IRQS NR_IRQS +#endif + + extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); @@ -123,6 +185,15 @@ #define INTC_IPRF 0xa400001cUL #endif +#define PORT_PACR 0xa4000100UL +#define PORT_PBCR 0xa4000102UL +#define PORT_PCCR 0xa4000104UL +#define PORT_PFCR 0xa400010aUL +#define PORT_PADR 0xa4000120UL +#define PORT_PBDR 0xa4000122UL +#define PORT_PCDR 0xa4000124UL +#define PORT_PFDR 0xa400012aUL + #define IRQ0_IRQ 32 #define IRQ1_IRQ 33 #define IRQ2_IRQ 34 @@ -130,19 +201,19 @@ #define IRQ4_IRQ 36 #define IRQ5_IRQ 37 -#define IRQ0_IRP_ADDR INTC_IPRC -#define IRQ1_IRP_ADDR INTC_IPRC -#define IRQ2_IRP_ADDR INTC_IPRC -#define IRQ3_IRP_ADDR INTC_IPRC -#define IRQ4_IRP_ADDR INTC_IPRD -#define IRQ5_IRP_ADDR INTC_IPRD - -#define IRQ0_IRP_POS 0 -#define IRQ1_IRP_POS 1 -#define IRQ2_IRP_POS 2 -#define IRQ3_IRP_POS 3 -#define IRQ4_IRP_POS 0 -#define IRQ5_IRP_POS 1 +#define IRQ0_IPR_ADDR INTC_IPRC +#define IRQ1_IPR_ADDR INTC_IPRC +#define IRQ2_IPR_ADDR INTC_IPRC +#define IRQ3_IPR_ADDR INTC_IPRC +#define IRQ4_IPR_ADDR INTC_IPRD +#define IRQ5_IPR_ADDR INTC_IPRD + +#define IRQ0_IPR_POS 0 +#define IRQ1_IPR_POS 1 +#define IRQ2_IPR_POS 2 +#define IRQ3_IPR_POS 3 +#define IRQ4_IPR_POS 0 +#define IRQ5_IPR_POS 1 #define IRQ0_PRIORITY 1 #define IRQ1_PRIORITY 1 @@ -150,21 +221,77 @@ #define IRQ3_PRIORITY 1 #define IRQ4_PRIORITY 1 #define IRQ5_PRIORITY 1 -#endif -extern int hd64461_irq_demux(int irq); +#define PINT0_IRQ 40 +#define PINT8_IRQ 41 + +#define PINT0_IPR_ADDR INTC_IPRD +#define PINT8_IPR_ADDR INTC_IPRD + +#define PINT0_IPR_POS 3 +#define PINT8_IPR_POS 2 +#define PINT0_PRIORITY 2 +#define PINT8_PRIORITY 2 +extern int ipr_irq_demux(int irq); +#define __irq_demux(irq) ipr_irq_demux(irq) + +#else +#define __irq_demux(irq) irq +#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */ + +#ifdef CONFIG_CPU_SUBTYPE_ST40STB1 +#define INTC2_FIRST_IRQ 64 +#define NR_INTC2_IRQS 25 + +#define INTC2_BASE0 0xfe080000 +#define INTC2_INTC2MODE (INTC2_BASE0+0x80) + +#define INTC2_INTPRI_OFFSET 0x00 +#define INTC2_INTREQ_OFFSET 0x20 +#define INTC2_INTMSK_OFFSET 0x40 +#define INTC2_INTMSKCLR_OFFSET 0x60 + +extern void make_intc2_irq(unsigned int irq,unsigned int addr, + unsigned int group,int pos,int priority); + +#endif + #ifdef CONFIG_SH_GENERIC + extern __inline__ int irq_demux(int irq) { if (sh_mv.mv_irq_demux) { irq = sh_mv.mv_irq_demux(irq); } - return irq; + return __irq_demux(irq); } + #elif defined(CONFIG_HD64461) + +extern int hd64461_irq_demux(int irq); #define irq_demux(irq) hd64461_irq_demux(irq) + +#elif defined(CONFIG_HD64465) + +extern int hd64465_irq_demux(int irq); +#define irq_demux(irq) hd64465_irq_demux(irq) + +#elif defined(CONFIG_SH_EC3104) + +extern int ec3104_irq_demux(int irq); +#define irq_demux ec3104_irq_demux + +#elif defined(CONFIG_SH_CAT68701) + +extern int cat68701_irq_demux(int irq); +#define irq_demux cat68701_irq_demux + #else -#define irq_demux(irq) irq + +#define irq_demux(irq) __irq_demux(irq) + #endif + + #endif /* __ASM_SH_IRQ_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/keyboard-ec3104.h linux/include/asm-sh/keyboard-ec3104.h --- v2.4.3/linux/include/asm-sh/keyboard-ec3104.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/keyboard-ec3104.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,17 @@ +extern unsigned char ec3104_kbd_sysrq_xlate[]; +extern int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int ec3104_kbd_getkeycode(unsigned int scancode); +extern int ec3104_kbd_translate(unsigned char, unsigned char *, char); +extern char ec3104_kbd_unexpected_up(unsigned char); +extern void ec3104_kbd_leds(unsigned char); +extern void ec3104_kbd_init_hw(void); + +#define SYSRQ_KEY 0x54 + +#define kbd_sysrq_xlate ec3104_kbd_sysrq_xlate +#define kbd_setkeycode ec3104_kbd_setkeycode +#define kbd_getkeycode ec3104_kbd_getkeycode +#define kbd_translate ec3104_kbd_translate +#define kbd_unexpected_up ec3104_kbd_unexpected_up +#define kbd_leds ec3104_kbd_leds +#define kbd_init_hw ec3104_kbd_init_hw diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/keyboard.h linux/include/asm-sh/keyboard.h --- v2.4.3/linux/include/asm-sh/keyboard.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/keyboard.h Wed Apr 11 21:24:52 2001 @@ -4,8 +4,12 @@ * $Id: keyboard.h,v 1.1 2000/06/10 21:45:48 yaegashi Exp $ */ +#include <linux/config.h> #include <asm/machvec.h> +#ifdef CONFIG_SH_EC3104 +#include <asm/keyboard-ec3104.h> +#else static __inline__ int kbd_setkeycode(unsigned int scancode, unsigned int keycode) { @@ -34,6 +38,7 @@ } extern void hp600_kbd_init_hw(void); +extern void dreamcast_kbd_init_hw(void); static __inline__ void kbd_init_hw(void) { @@ -42,4 +47,5 @@ } } +#endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/machvec.h linux/include/asm-sh/machvec.h --- v2.4.3/linux/include/asm-sh/machvec.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/machvec.h Wed Apr 11 21:24:52 2001 @@ -13,45 +13,45 @@ #include <linux/config.h> #include <linux/types.h> +struct timeval; + struct sh_machine_vector { const char *mv_name; int mv_nr_irqs; - unsigned long (*mv_inb)(unsigned int); - unsigned long (*mv_inw)(unsigned int); - unsigned long (*mv_inl)(unsigned int); - void (*mv_outb)(unsigned long, unsigned int); - void (*mv_outw)(unsigned long, unsigned int); - void (*mv_outl)(unsigned long, unsigned int); - - unsigned long (*mv_inb_p)(unsigned int); - unsigned long (*mv_inw_p)(unsigned int); - unsigned long (*mv_inl_p)(unsigned int); - void (*mv_outb_p)(unsigned long, unsigned int); - void (*mv_outw_p)(unsigned long, unsigned int); - void (*mv_outl_p)(unsigned long, unsigned int); - - void (*mv_insb)(unsigned int port, void *addr, unsigned long count); - void (*mv_insw)(unsigned int port, void *addr, unsigned long count); - void (*mv_insl)(unsigned int port, void *addr, unsigned long count); - void (*mv_outsb)(unsigned int port, const void *addr, unsigned long count); - void (*mv_outsw)(unsigned int port, const void *addr, unsigned long count); - void (*mv_outsl)(unsigned int port, const void *addr, unsigned long count); - - unsigned long (*mv_readb)(unsigned long); - unsigned long (*mv_readw)(unsigned long); - unsigned long (*mv_readl)(unsigned long); + unsigned char (*mv_inb)(unsigned long); + unsigned short (*mv_inw)(unsigned long); + unsigned int (*mv_inl)(unsigned long); + void (*mv_outb)(unsigned char, unsigned long); + void (*mv_outw)(unsigned short, unsigned long); + void (*mv_outl)(unsigned int, unsigned long); + + unsigned char (*mv_inb_p)(unsigned long); + unsigned short (*mv_inw_p)(unsigned long); + unsigned int (*mv_inl_p)(unsigned long); + void (*mv_outb_p)(unsigned char, unsigned long); + void (*mv_outw_p)(unsigned short, unsigned long); + void (*mv_outl_p)(unsigned int, unsigned long); + + void (*mv_insb)(unsigned long port, void *addr, unsigned long count); + void (*mv_insw)(unsigned long port, void *addr, unsigned long count); + void (*mv_insl)(unsigned long port, void *addr, unsigned long count); + void (*mv_outsb)(unsigned long port, const void *addr, unsigned long count); + void (*mv_outsw)(unsigned long port, const void *addr, unsigned long count); + void (*mv_outsl)(unsigned long port, const void *addr, unsigned long count); + + unsigned char (*mv_readb)(unsigned long); + unsigned short (*mv_readw)(unsigned long); + unsigned int (*mv_readl)(unsigned long); void (*mv_writeb)(unsigned char, unsigned long); void (*mv_writew)(unsigned short, unsigned long); void (*mv_writel)(unsigned int, unsigned long); void* (*mv_ioremap)(unsigned long offset, unsigned long size); - void* (*mv_ioremap_nocache)(unsigned long offset, unsigned long size); void (*mv_iounmap)(void *addr); - unsigned long (*mv_port2addr)(unsigned long offset); unsigned long (*mv_isa_port2addr)(unsigned long offset); int (*mv_irq_demux)(int irq); @@ -63,9 +63,17 @@ void (*mv_heartbeat)(void); + void (*mv_rtc_gettimeofday)(struct timeval *tv); + int (*mv_rtc_settimeofday)(const struct timeval *tv); + unsigned int mv_hw_se : 1; unsigned int mv_hw_hp600 : 1; + unsigned int mv_hw_hp620 : 1; + unsigned int mv_hw_hp680 : 1; + unsigned int mv_hw_hp690 : 1; unsigned int mv_hw_hd64461 : 1; + unsigned int mv_hw_hd64465 : 1; + unsigned int mv_hw_dreamcast : 1; }; extern struct sh_machine_vector sh_mv; @@ -74,7 +82,12 @@ #ifdef CONFIG_SH_GENERIC #define MACH_SE (sh_mv.mv_hw_se) #define MACH_HP600 (sh_mv.mv_hw_hp600) +#define MACH_HP620 (sh_mv.mv_hw_hp620) +#define MACH_HP680 (sh_mv.mv_hw_hp680) +#define MACH_HP690 (sh_mv.mv_hw_hp690) #define MACH_HD64461 (sh_mv.mv_hw_hd64461) +#define MACH_HD64465 (sh_mv.mv_hw_hd64465) +#define MACH_DREAMCAST (sh_mv.mv_hw_dreamcast) #else # ifdef CONFIG_SH_SOLUTION_ENGINE # define MACH_SE 1 @@ -86,10 +99,40 @@ # else # define MACH_HP600 0 # endif +# ifdef CONFIG_SH_HP620 +# define MACH_HP620 1 +# else +# define MACH_HP620 0 +# endif +# ifdef CONFIG_SH_HP680 +# define MACH_HP680 1 +# else +# define MACH_HP680 0 +# endif +# ifdef CONFIG_SH_HP690 +# define MACH_HP690 1 +# else +# define MACH_HP690 0 +# endif # ifdef CONFIG_HD64461 # define MACH_HD64461 1 # else # define MACH_HD64461 0 +# endif +# ifdef CONFIG_HD64465 +# define MACH_HD64465 1 +# else +# define MACH_HD64465 0 +# endif +# ifdef CONFIG_SH_EC3104 +# define MACH_EC3104 1 +# else +# define MACH_EC3104 0 +# endif +# ifdef CONFIG_SH_DREAMCAST +# define MACH_DREAMCAST 1 +# else +# define MACH_DREAMCAST 0 # endif #endif diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h --- v2.4.3/linux/include/asm-sh/pci.h Mon Oct 2 11:57:34 2000 +++ linux/include/asm-sh/pci.h Wed Apr 11 21:24:52 2001 @@ -7,13 +7,13 @@ already-configured bus numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the loader */ -#define pcibios_assign_all_busses() 0 +#define pcibios_assign_all_busses() 1 /* These are currently the correct values for the STM overdrive board. * We need some way of setting this on a board specific way, it will * not be the same on other boards I think */ -#if 1 /* def CONFIG_SH_OVERDRIVE */ +#if 1 /* def CONFIG_SH_7750_OVERDRIVE || def CONFIG_CPU_SUBTYPE_ST40STB1 */ #define PCIBIOS_MIN_IO 0x2000 #define PCIBIOS_MIN_MEM 0x10000000 #endif @@ -70,6 +70,8 @@ static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,int directoin) { + + flush_cache_all(); return virt_to_bus(ptr); } @@ -104,6 +106,7 @@ static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,int direction) { + flush_cache_all(); return nents; } @@ -145,6 +148,19 @@ { /* Nothing to do */ } + + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; +} + + /* These macros should be used after a pci_map_sg call has been done * to get bus addresses of each of the SG entries and their lengths. diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgalloc-2level.h linux/include/asm-sh/pgalloc-2level.h --- v2.4.3/linux/include/asm-sh/pgalloc-2level.h Fri Oct 13 12:06:52 2000 +++ linux/include/asm-sh/pgalloc-2level.h Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -#ifndef __ASM_SH_PGALLOC_2LEVEL_H -#define __ASM_SH_PGALLOC_2LEVEL_H - -/* - * traditional two-level paging, page table allocation routines: - */ - -static __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -static __inline__ void free_pmd_fast(pmd_t *pmd) { } -static __inline__ void free_pmd_slow(pmd_t *pmd) { } - -static __inline__ pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - if (!pgd) - BUG(); - return (pmd_t *) pgd; -} - -#endif /* __ASM_SH_PGALLOC_2LEVEL_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgalloc.h linux/include/asm-sh/pgalloc.h --- v2.4.3/linux/include/asm-sh/pgalloc.h Fri Oct 13 12:06:52 2000 +++ linux/include/asm-sh/pgalloc.h Wed Apr 11 21:24:52 2001 @@ -10,23 +10,22 @@ #define pte_quicklist (current_cpu_data.pte_quick) #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) -#include <asm/pgalloc-2level.h> +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Allocate and free page tables. */ static __inline__ pgd_t *get_pgd_slow(void) { unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t)); - pgd_t *ret = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL); + pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL); - if (ret) - memset(ret, 0, pgd_size); + if (pgd) + memset(pgd, 0, pgd_size); - return ret; + return pgd; } static __inline__ pgd_t *get_pgd_fast(void) @@ -54,14 +53,21 @@ kfree(pgd); } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} -static __inline__ pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; - if((ret = (unsigned long *)pte_quicklist) != NULL) { + if ((ret = (unsigned long *)pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; pgtable_cache_size--; @@ -69,65 +75,21 @@ return (pte_t *)ret; } -static __inline__ void free_pte_fast(pte_t *pte) +static __inline__ void pte_free_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -static __inline__ void free_pte_slow(pte_t *pte) +static __inline__ void pte_free_slow(pte_t *pte) { free_page((unsigned long)pte); } -#define pte_free_kernel(pte) free_pte_slow(pte) -#define pte_free(pte) free_pte_slow(pte) -#define pgd_free(pgd) free_pgd_slow(pgd) -#define pgd_alloc() get_pgd_fast() - -static __inline__ pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) -{ - if (!pmd) - BUG(); - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_kernel_slow(pmd, address); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page))); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -static __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) - goto getnew; - if (pmd_bad(*pmd)) - goto fix; - return (pte_t *)pmd_page(*pmd) + address; -getnew: -{ - unsigned long page = (unsigned long) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page))); - return (pte_t *)page + address; -} -fix: - __handle_bad_pmd(pmd); - return NULL; -} +#define pte_free(pte) pte_free_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc() get_pgd_fast() /* * allocating and freeing a pmd is trivial: the 1-entry pmd is @@ -137,8 +99,12 @@ { } -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc +#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(x) do { } while (0) +#define pmd_free_fast(x) do { } while (0) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() extern int do_check_pgt_cache(int, int); diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgtable-2level.h linux/include/asm-sh/pgtable-2level.h --- v2.4.3/linux/include/asm-sh/pgtable-2level.h Thu Jan 4 13:19:13 2001 +++ linux/include/asm-sh/pgtable-2level.h Wed Apr 11 21:24:52 2001 @@ -32,7 +32,7 @@ static inline int pgd_none(pgd_t pgd) { return 0; } static inline int pgd_bad(pgd_t pgd) { return 0; } static inline int pgd_present(pgd_t pgd) { return 1; } -#define pgd_clear(xp) do { } while (0) +static inline void pgd_clear (pgd_t * pgd) { } /* * Certain architectures need to do special things when PTEs diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h --- v2.4.3/linux/include/asm-sh/pgtable.h Sun Jan 28 18:56:00 2001 +++ linux/include/asm-sh/pgtable.h Wed Apr 11 21:24:52 2001 @@ -166,12 +166,6 @@ #define __S110 PAGE_SHARED #define __S111 PAGE_SHARED -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd(pmd_t * pmd); -extern void __handle_bad_pmd_kernel(pmd_t * pmd); - #define pte_none(x) (!pte_val(x)) #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0) diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/processor.h linux/include/asm-sh/processor.h --- v2.4.3/linux/include/asm-sh/processor.h Thu Jan 4 13:19:13 2001 +++ linux/include/asm-sh/processor.h Wed Apr 11 21:24:52 2001 @@ -24,6 +24,7 @@ CPU_SH7708, /* Represents 7707, 7708, 7708S, 7708R, 7709 */ CPU_SH7729, /* Represents 7709A, 7729 */ CPU_SH7750, + CPU_ST40STB1, CPU_SH_NONE }; diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/semaphore.h linux/include/asm-sh/semaphore.h --- v2.4.3/linux/include/asm-sh/semaphore.h Sun Mar 5 09:33:55 2000 +++ linux/include/asm-sh/semaphore.h Tue Apr 17 17:19:31 2001 @@ -13,6 +13,7 @@ */ #include <linux/spinlock.h> +#include <linux/rwsem.h> #include <asm/system.h> #include <asm/atomic.h> @@ -134,151 +135,6 @@ #endif if (atomic_inc_return(&sem->count) <= 0) __up(sem); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * SuperH version by Niibe Yutaka - */ -struct rw_semaphore { - atomic_t count; - volatile unsigned char write_bias_granted; - volatile unsigned char read_bias_granted; - volatile unsigned char pad1; - volatile unsigned char pad2; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#define RW_LOCK_BIAS 0x01000000 - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->read_bias_granted = 0; - sem->write_bias_granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -extern inline void down_read(struct rw_semaphore *sem) -{ - int saved = atomic_read(&sem->count), new; -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - if ((new = atomic_dec_return(&sem->count)) < 0) - __down_read(sem, (new < 0 && saved >=0)); -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ - int saved = atomic_read(&sem->count), new; -#if WAITQUEUE_DEBUG - if (sem->__magic != (long)&sem->__magic) - BUG(); -#endif - if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count)) != 0) - __down_write(sem, (new < 0 && saved >=0)); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -extern inline void __up_read(struct rw_semaphore *sem) -{ - if (atomic_inc_return(&sem->count) == 0) - __rwsem_wake(sem); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -extern inline void __up_write(struct rw_semaphore *sem) -{ - int saved = atomic_read(&sem->count), new; - - new = atomic_add_return(RW_LOCK_BIAS, &sem->count); - if (saved < 0 && new >= 0) - __rwsem_wake(sem); -} - -extern inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -extern inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (sem->read_bias_granted) - BUG(); - if (sem->write_bias_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); } #endif /* __ASM_SH_SEMAPHORE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/serial-ec3104.h linux/include/asm-sh/serial-ec3104.h --- v2.4.3/linux/include/asm-sh/serial-ec3104.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sh/serial-ec3104.h Wed Apr 11 21:24:52 2001 @@ -0,0 +1,24 @@ +#include <asm/ec3104.h> +/* Naturally we don't know the exact value but 115200 baud has a divisor + * of 9 and 19200 baud has a divisor of 52, so this seems like a good + * guess. */ +#define BASE_BAUD (16800000 / 16) + +#define RS_TABLE_SIZE 3 + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +/* there is a fourth serial port with the expected values as well, but + * it's got the keyboard controller behind it so we can't really use it + * (without moving the keyboard driver to userspace, which doesn't sound + * like a very good idea) */ +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x11C00, EC3104_IRQBASE+7, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x12000, EC3104_IRQBASE+8, STD_COM_FLAGS }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0x12400, EC3104_IRQBASE+9, STD_COM_FLAGS }, /* ttyS2 */ + +#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS + +/* XXX: This should be moved ino irq.h */ +#define irq_cannonicalize(x) (x) diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/serial.h linux/include/asm-sh/serial.h --- v2.4.3/linux/include/asm-sh/serial.h Sat Jul 22 07:42:06 2000 +++ linux/include/asm-sh/serial.h Wed Apr 11 21:24:52 2001 @@ -7,6 +7,13 @@ #ifndef _ASM_SERIAL_H #define _ASM_SERIAL_H +#include <linux/config.h> +#include <linux/kernel.h> + +#ifdef CONFIG_SH_EC3104 +#include <asm/serial-ec3104.h> +#else + /* * This assumes you have a 1.8432 MHz clock for your UART. * @@ -16,18 +23,32 @@ */ #define BASE_BAUD ( 1843200 / 16 ) -#define RS_TABLE_SIZE 2 - #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#ifdef CONFIG_HD64465 +#include <asm/hd64465.h> + +#define RS_TABLE_SIZE 1 + +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */ + +#else + +#define RS_TABLE_SIZE 2 + #define STD_SERIAL_PORT_DEFNS \ /* UART CLK PORT IRQ FLAGS */ \ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS } /* ttyS1 */ +#endif + #define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS /* XXX: This should be moved ino irq.h */ #define irq_cannonicalize(x) (x) +#endif #endif /* _ASM_SERIAL_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sh/sigcontext.h linux/include/asm-sh/sigcontext.h --- v2.4.3/linux/include/asm-sh/sigcontext.h Mon Apr 24 13:54:17 2000 +++ linux/include/asm-sh/sigcontext.h Wed Apr 11 21:24:52 2001 @@ -16,7 +16,7 @@ #if defined(__SH4__) /* FPU registers */ unsigned long sc_fpregs[16]; - unsigned long long sc_xdregs[8]; + unsigned long sc_xfpregs[16]; unsigned int sc_fpscr; unsigned int sc_fpul; unsigned int sc_ownedfp; diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/kmap_types.h linux/include/asm-sparc/kmap_types.h --- v2.4.3/linux/include/asm-sparc/kmap_types.h Fri Aug 4 18:16:11 2000 +++ linux/include/asm-sparc/kmap_types.h Thu Apr 12 12:11:39 2001 @@ -4,6 +4,8 @@ enum km_type { KM_BOUNCE_READ, KM_BOUNCE_WRITE, + KM_SKB_DATA, + KM_SKB_DATA_SOFTIRQ, KM_TYPE_NR }; diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/perfctr.h linux/include/asm-sparc/perfctr.h --- v2.4.3/linux/include/asm-sparc/perfctr.h Tue Oct 27 09:52:21 1998 +++ linux/include/asm-sparc/perfctr.h Thu Apr 12 12:10:25 2001 @@ -60,10 +60,10 @@ #ifndef __KERNEL__ #define PRIV 0x00000001 -#define USR 0x00000002 -#define SYS 0x00000004 +#define SYS 0x00000002 +#define USR 0x00000004 -/* Pic.S0 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT 0x00000000 #define INSTR_CNT 0x00000010 #define DISPATCH0_IC_MISS 0x00000020 @@ -77,7 +77,38 @@ #define EC_SNOOP_INV 0x000000E0 #define EC_RD_HIT 0x000000F0 -/* Pic.S1 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT 0x00000000 +#define US3_INSTR_CNT 0x00000010 +#define US3_DISPATCH0_IC_MISS 0x00000020 +#define US3_DISPATCH0_BR_TGT 0x00000030 +#define US3_DISPATCH0_2ND_BR 0x00000040 +#define US3_RSTALL_STOREQ 0x00000050 +#define US3_RSTALL_IU_USE 0x00000060 +#define US3_IC_REF 0x00000080 +#define US3_DC_RD 0x00000090 +#define US3_DC_WR 0x000000a0 +#define US3_EC_REF 0x000000c0 +#define US3_EC_WR_HIT_RTO 0x000000d0 +#define US3_EC_SNOOP_INV 0x000000e0 +#define US3_EC_RD_MISS 0x000000f0 +#define US3_PC_PORT0_RD 0x00000100 +#define US3_SI_SNOOP 0x00000110 +#define US3_SI_CIQ_FLOW 0x00000120 +#define US3_SI_OWNED 0x00000130 +#define US3_SW_COUNT_0 0x00000140 +#define US3_IU_BR_MISS_TAKEN 0x00000150 +#define US3_IU_BR_COUNT_TAKEN 0x00000160 +#define US3_DISP_RS_MISPRED 0x00000170 +#define US3_FA_PIPE_COMPL 0x00000180 +#define US3_MC_READS_0 0x00000200 +#define US3_MC_READS_1 0x00000210 +#define US3_MC_READS_2 0x00000220 +#define US3_MC_READS_3 0x00000230 +#define US3_MC_STALLS_0 0x00000240 +#define US3_MC_STALLS_2 0x00000250 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT_D1 0x00000000 #define INSTR_CNT_D1 0x00000800 #define DISPATCH0_IC_MISPRED 0x00001000 @@ -90,6 +121,47 @@ #define EC_WB 0x00006800 #define EC_SNOOP_CB 0x00007000 #define EC_IT_HIT 0x00007800 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT_D1 0x00000000 +#define US3_INSTR_CNT_D1 0x00000800 +#define US3_DISPATCH0_MISPRED 0x00001000 +#define US3_IC_MISS_CANCELLED 0x00001800 +#define US3_RE_ENDIAN_MISS 0x00002000 +#define US3_RE_FPU_BYPASS 0x00002800 +#define US3_RE_DC_MISS 0x00003000 +#define US3_RE_EC_MISS 0x00003800 +#define US3_IC_MISS 0x00004000 +#define US3_DC_RD_MISS 0x00004800 +#define US3_DC_WR_MISS 0x00005000 +#define US3_RSTALL_FP_USE 0x00005800 +#define US3_EC_MISSES 0x00006000 +#define US3_EC_WB 0x00006800 +#define US3_EC_SNOOP_CB 0x00007000 +#define US3_EC_IC_MISS 0x00007800 +#define US3_RE_PC_MISS 0x00008000 +#define US3_ITLB_MISS 0x00008800 +#define US3_DTLB_MISS 0x00009000 +#define US3_WC_MISS 0x00009800 +#define US3_WC_SNOOP_CB 0x0000a000 +#define US3_WC_SCRUBBED 0x0000a800 +#define US3_WC_WB_WO_READ 0x0000b000 +#define US3_PC_SOFT_HIT 0x0000c000 +#define US3_PC_SNOOP_INV 0x0000c800 +#define US3_PC_HARD_HIT 0x0000d000 +#define US3_PC_PORT1_RD 0x0000d800 +#define US3_SW_COUNT_1 0x0000e000 +#define US3_IU_STAT_BR_MIS_UNTAKEN 0x0000e800 +#define US3_IU_STAT_BR_COUNT_UNTAKEN 0x0000f000 +#define US3_PC_MS_MISSES 0x0000f800 +#define US3_MC_WRITES_0 0x00010800 +#define US3_MC_WRITES_1 0x00011000 +#define US3_MC_WRITES_2 0x00011800 +#define US3_MC_WRITES_3 0x00012000 +#define US3_MC_STALLS_1 0x00012800 +#define US3_MC_STALLS_3 0x00013000 +#define US3_RE_RAW_MISS 0x00013800 +#define US3_FM_PIPE_COMPLETION 0x00014000 struct vcounter_struct { unsigned long long vcnt0; diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h --- v2.4.3/linux/include/asm-sparc/processor.h Mon Jan 1 10:37:41 2001 +++ linux/include/asm-sparc/processor.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.80 2000/12/31 10:05:43 davem Exp $ +/* $Id: processor.h,v 1.81 2001/03/27 02:36:37 davem Exp $ * include/asm-sparc/processor.h * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) @@ -90,7 +90,6 @@ #define SPARC_FLAG_KTHREAD 0x1 /* task is a kernel thread */ #define SPARC_FLAG_UNALIGNED 0x2 /* is allowed to do unaligned accesses */ -#define SPARC_FLAG_MMAPSHARED 0x4 /* task wants a shared mmap */ #define INIT_MMAP { &init_mm, (0), (0), \ NULL, __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h --- v2.4.3/linux/include/asm-sparc/semaphore.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc/semaphore.h Tue Apr 17 17:19:31 2001 @@ -7,6 +7,7 @@ #include <asm/atomic.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -207,201 +208,6 @@ : "0" (increment), "r" (ptr), "i" (__up) : "g3", "g4", "g7", "memory", "cc"); } - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subtracting - * BIAS once per CPU will result in the int remaining - * negative. - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - */ -#define RW_LOCK_BIAS 0x01000000 - -struct rw_semaphore { - int count; - unsigned char lock; - unsigned char read_not_granted; - unsigned char write_not_granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ (count), 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -static inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RW_LOCK_BIAS; - sem->lock = 0; - sem->read_not_granted = 0xff; - sem->write_not_granted = 0xff; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -extern void ___down_read(/* Special calling convention */ void); -extern void ___down_write(/* Special calling convention */ void); -extern void ___up_read(/* Special calling convention */ void); -extern void ___up_write(/* Special calling convention */ void); - -static inline void down_read(struct rw_semaphore *sem) -{ - register volatile int *ptr asm("g1"); - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - ptr = &sem->count; - - __asm__ __volatile__(" - mov %%o7, %%g4 - call %1 - add %%o7, 8, %%o7 - " - :: "r" (ptr), "i" (___down_read) - : "g2", "g3", "g4", "g7", "memory", "cc"); -#if WAITQUEUE_DEBUG - if (!sem->write_not_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -static inline void down_write(struct rw_semaphore *sem) -{ - register volatile int *ptr asm("g1"); - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - ptr = &sem->count; - - __asm__ __volatile__(" - mov %%o7, %%g4 - call %1 - add %%o7, 8, %%o7 - " - :: "r" (ptr), "i" (___down_write) - : "g2", "g3", "g4", "g7", "memory", "cc"); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (!sem->read_not_granted) - BUG(); - if (!sem->write_not_granted) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -static inline void __up_read(struct rw_semaphore *sem) -{ - register volatile int *ptr asm("g1"); - - ptr = &sem->count; - - __asm__ __volatile__(" - mov %%o7, %%g4 - call %1 - add %%o7, 8, %%o7 - " - :: "r" (ptr), "i" (___up_read) - : "g2", "g3", "g4", "g7", "memory", "cc"); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -static inline void __up_write(struct rw_semaphore *sem) -{ - register volatile int *ptr asm("g1"); - - ptr = &sem->count; - - __asm__ __volatile__(" - mov %%o7, %%g4 - call %1 - add %%o7, 8, %%o7 - " - :: "r" (ptr), "i" (___up_write) - : "g2", "g3", "g4", "g7", "memory", "cc"); -} - -static inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (!sem->write_not_granted) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -static inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (!sem->read_not_granted) - BUG(); - if (!sem->write_not_granted) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); -} #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/asi.h linux/include/asm-sparc64/asi.h --- v2.4.3/linux/include/asm-sparc64/asi.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc64/asi.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: asi.h,v 1.4 2001/03/15 02:08:46 davem Exp $ */ +/* $Id: asi.h,v 1.5 2001/03/29 11:47:47 davem Exp $ */ #ifndef _SPARC64_ASI_H #define _SPARC64_ASI_H @@ -80,6 +80,7 @@ #define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag */ #define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ #define ASI_BLK_AIUS 0x71 /* Secondary, user, block load/store */ +#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller registers */ #define ASI_EC_DATA 0x74 /* (III) E-cache data staging register */ #define ASI_EC_CTRL 0x75 /* (III) E-cache control register */ #define ASI_EC_W 0x76 /* E-cache diag write access */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/bbc.h linux/include/asm-sparc64/bbc.h --- v2.4.3/linux/include/asm-sparc64/bbc.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc64/bbc.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: bbc.h,v 1.1 2001/03/24 06:03:03 davem Exp $ +/* $Id: bbc.h,v 1.2 2001/03/26 23:47:18 davem Exp $ * bbc.h: Defines for BootBus Controller found on UltraSPARC-III * systems. * @@ -89,7 +89,7 @@ * is asserted can be controlled by this regiser. */ #define BBC_WDACTION_RST 0x01 /* When set, watchdog causes system reset. - * When clear, all cpus receive XIR reset. + * When clear, BBC ignores watchdog signal. */ #define BBC_WDACTION_RESV 0xfe /* Reserved */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h --- v2.4.3/linux/include/asm-sparc64/bitops.h Tue Oct 3 09:24:41 2000 +++ linux/include/asm-sparc64/bitops.h Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.31 2000/09/23 02:09:21 davem Exp $ +/* $Id: bitops.h,v 1.32 2001/04/14 01:12:16 davem Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -9,16 +9,24 @@ #include <asm/byteorder.h> -extern long __test_and_set_bit(unsigned long nr, volatile void *addr); -extern long __test_and_clear_bit(unsigned long nr, volatile void *addr); -extern long __test_and_change_bit(unsigned long nr, volatile void *addr); - -#define test_and_set_bit(nr,addr) (__test_and_set_bit(nr,addr)!=0) -#define test_and_clear_bit(nr,addr) (__test_and_clear_bit(nr,addr)!=0) -#define test_and_change_bit(nr,addr) (__test_and_change_bit(nr,addr)!=0) -#define set_bit(nr,addr) ((void)__test_and_set_bit(nr,addr)) -#define clear_bit(nr,addr) ((void)__test_and_clear_bit(nr,addr)) -#define change_bit(nr,addr) ((void)__test_and_change_bit(nr,addr)) +extern long ___test_and_set_bit(unsigned long nr, volatile void *addr); +extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr); +extern long ___test_and_change_bit(unsigned long nr, volatile void *addr); + +#define test_and_set_bit(nr,addr) (___test_and_set_bit(nr,addr)!=0) +#define test_and_clear_bit(nr,addr) (___test_and_clear_bit(nr,addr)!=0) +#define test_and_change_bit(nr,addr) (___test_and_change_bit(nr,addr)!=0) +#define set_bit(nr,addr) ((void)___test_and_set_bit(nr,addr)) +#define clear_bit(nr,addr) ((void)___test_and_clear_bit(nr,addr)) +#define change_bit(nr,addr) ((void)___test_and_change_bit(nr,addr)) + +/* "non-atomic" versions, nothing special for now... */ +#define __set_bit(X,Y) set_bit(X,Y) +#define __clear_bit(X,Y) clear_bit(X,Y) +#define __change_bit(X,Y) change_bit(X,Y) +#define __test_and_set_bit(X,Y) test_and_set_bit(X,Y) +#define __test_and_clear_bit(X,Y) test_and_clear_bit(X,Y) +#define __test_and_change_bit(X,Y) test_and_change_bit(X,Y) #define smp_mb__before_clear_bit() do { } while(0) #define smp_mb__after_clear_bit() do { } while(0) @@ -170,13 +178,13 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) -extern long __test_and_set_le_bit(int nr, volatile void *addr); -extern long __test_and_clear_le_bit(int nr, volatile void *addr); +extern long ___test_and_set_le_bit(int nr, volatile void *addr); +extern long ___test_and_clear_le_bit(int nr, volatile void *addr); -#define test_and_set_le_bit(nr,addr) (__test_and_set_le_bit(nr,addr)!=0) -#define test_and_clear_le_bit(nr,addr) (__test_and_clear_le_bit(nr,addr)!=0) -#define set_le_bit(nr,addr) ((void)__test_and_set_le_bit(nr,addr)) -#define clear_le_bit(nr,addr) ((void)__test_and_clear_le_bit(nr,addr)) +#define test_and_set_le_bit(nr,addr) (___test_and_set_le_bit(nr,addr)!=0) +#define test_and_clear_le_bit(nr,addr) (___test_and_clear_le_bit(nr,addr)!=0) +#define set_le_bit(nr,addr) ((void)___test_and_set_le_bit(nr,addr)) +#define clear_le_bit(nr,addr) ((void)___test_and_clear_le_bit(nr,addr)) extern __inline__ int test_le_bit(int nr, __const__ void * addr) { diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/chafsr.h linux/include/asm-sparc64/chafsr.h --- v2.4.3/linux/include/asm-sparc64/chafsr.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/chafsr.h Thu Apr 12 12:10:25 2001 @@ -0,0 +1,150 @@ +/* $Id: chafsr.h,v 1.1 2001/03/28 10:56:34 davem Exp $ */ +#ifndef _SPARC64_CHAFSR_H +#define _SPARC64_CHAFSR_H + +/* Cheetah Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */ + +/* All bits of this register except M_SYNDROME and E_SYNDROME are + * read, write 1 to clear. M_SYNDROME and E_SYNDROME are read-only. + */ + +/* Multiple errors of the same type have occurred. This bit is set when + * an uncorrectable error or a SW correctable error occurs and the status + * bit to report that error is already set. When multiple errors of + * different types are indicated by setting multiple status bits. + * + * This bit is not set if multiple HW corrected errors with the same + * status bit occur, only uncorrectable and SW correctable ones have + * this behavior. + * + * This bit is not set when multiple ECC errors happen within a single + * 64-byte system bus transaction. Only the first ECC error in a 16-byte + * subunit will be logged. All errors in subsequent 16-byte subunits + * from the same 64-byte transaction are ignored. + */ +#define CHAFSR_ME 0x0020000000000000 + +/* Privileged state error has occurred. This is a capture of PSTATE.PRIV + * at the time the error is detected. + */ +#define CHAFSR_PRIV 0x0010000000000000 + +/* The following bits 51 (CHAFSR_PERR) to 33 (CHAFSR_CE) are sticky error + * bits and record the most recently detected errors. Bits accumulate + * errors that have been detected since the last write to clear the bit. + */ + +/* System interface protocol error. The processor asserts its' ERROR + * pin when this event occurs and it also logs a specific cause code + * into a JTAG scannable flop. + */ +#define CHAFSR_PERR 0x0008000000000000 + +/* Internal processor error. The processor asserts its' ERROR + * pin when this event occurs and it also logs a specific cause code + * into a JTAG scannable flop. + */ +#define CHAFSR_IERR 0x0004000000000000 + +/* System request parity error on incoming address */ +#define CHAFSR_ISAP 0x0002000000000000 + +/* HW Corrected system bus MTAG ECC error */ +#define CHAFSR_EMC 0x0001000000000000 + +/* Uncorrectable system bus MTAG ECC error */ +#define CHAFSR_EMU 0x0000800000000000 + +/* HW Corrected system bus data ECC error for read of interrupt vector */ +#define CHAFSR_IVC 0x0000400000000000 + +/* Uncorrectable system bus data ECC error for read of interrupt vector */ +#define CHAFSR_IVU 0x0000200000000000 + +/* Unmappeed error from system bus */ +#define CHAFSR_TO 0x0000100000000000 + +/* Bus error response from system bus */ +#define CHAFSR_BERR 0x0000080000000000 + +/* SW Correctable E-cache ECC error for instruction fetch or data access + * other than block load. + */ +#define CHAFSR_UCC 0x0000040000000000 + +/* Uncorrectable E-cache ECC error for instruction fetch or data access + * other than block load. + */ +#define CHAFSR_UCU 0x0000020000000000 + +/* Copyout HW Corrected ECC error */ +#define CHAFSR_CPC 0x0000010000000000 + +/* Copyout Uncorrectable ECC error */ +#define CHAFSR_CPU 0x0000008000000000 + +/* HW Corrected ECC error from E-cache for writeback */ +#define CHAFSR_WDC 0x0000004000000000 + +/* Uncorrectable ECC error from E-cache for writeback */ +#define CHAFSR_WDU 0x0000002000000000 + +/* HW Corrected ECC error from E-cache for store merge or block load */ +#define CHAFSR_EDC 0x0000001000000000 + +/* Uncorrectable ECC error from E-cache for store merge or block load */ +#define CHAFSR_EDU 0x0000000800000000 + +/* Uncorrectable system bus data ECC error for read of memory or I/O */ +#define CHAFSR_UE 0x0000000400000000 + +/* HW Corrected system bus data ECC error for read of memory or I/O */ +#define CHAFSR_CE 0x0000000200000000 + +#define CHAFSR_ERRORS (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP | CHAFSR_EMC | \ + CHAFSR_EMU | CHAFSR_IVC | CHAFSR_IVU | CHAFSR_TO | \ + CHAFSR_BERR | CHAFSR_UCC | CHAFSR_UCU | CHAFSR_CPC | \ + CHAFSR_CPU | CHAFSR_WDC | CHAFSR_WDU | CHAFSR_EDC | \ + CHAFSR_EDU | CHAFSR_UE | CHAFSR_CE) + +/* System bus MTAG ECC syndrome. This field captures the status of the + * first occurrence of the highest-priority error according to the M_SYND + * overwrite policy. After the AFSR sticky bit, corresponding to the error + * for which the M_SYND is reported, is cleared, the contents of the M_SYND + * field will be unchanged by will be unfrozen for further error capture. + */ +#define CHAFSR_M_SYNDROME 0x00000000000f0000 +#define CHAFSR_M_SYNDROME_SHIFT 16 + +/* System bus or E-cache data ECC syndrome. This field captures the status + * of the first occurrence of the highest-priority error according to the + * E_SYND overwrite policy. After the AFSR sticky bit, corresponding to the + * error for which the E_SYND is reported, is cleare, the contents of the E_SYND + * field will be unchanged but will be unfrozen for further error capture. + */ +#define CHAFSR_E_SYNDROME 0x00000000000001ff +#define CHAFSR_E_SYNDROME_SHIFT 0 + +/* The AFSR must be explicitly cleared by software, it is not cleared automatically + * by a read. Writes to bits <51:33> with bits set will clear the corresponding + * bits in the AFSR. Bits assosciated with disrupting traps must be cleared before + * interrupts are re-enabled to prevent multiple traps for the same error. I.e. + * PSTATE.IE and AFSR bits control delivery of disrupting traps. + * + * Since there is only one AFAR, when multiple events have been logged by the + * bits in the AFSR, at most one of these events will have its status captured + * in the AFAR. The highest priority of those event bits will get AFAR logging. + * The AFAR will be unlocked and available to capture the address of another event + * as soon as the one bit in AFSR that corresponds to the event logged in AFAR is + * cleared. For example, if AFSR.CE is detected, then AFSR.UE (which overwrites + * the AFAR), and AFSR.UE is cleared by not AFSR.CE, then the AFAR will be unlocked + * and ready for another event, even though AFSR.CE is still set. The same rules + * also apply to the M_SYNDROME and E_SYNDROME fields of the AFSR. + */ + +/* Software bit set by linux trap handlers to indicate that the trap was + * signalled at %tl >= 1. + */ +#define CHAFSR_TL1 0x8000000000000000 + +#endif /* _SPARC64_CHAFSR_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/chmctrl.h linux/include/asm-sparc64/chmctrl.h --- v2.4.3/linux/include/asm-sparc64/chmctrl.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/chmctrl.h Thu Apr 12 12:10:25 2001 @@ -0,0 +1,184 @@ +/* $Id: chmctrl.h,v 1.1 2001/03/29 11:43:28 davem Exp $ */ +#ifndef _SPARC64_CHMCTRL_H +#define _SPARC64_CHMCTRL_H + +/* Cheetah memory controller programmable registers. */ +#define CHMCTRL_TCTRL1 0x00 /* Memory Timing Control I */ +#define CHMCTRL_TCTRL2 0x08 /* Memory Timing Control II */ +#define CHMCTRL_TCTRL3 0x38 /* Memory Timing Control III */ +#define CHMCTRL_TCTRL4 0x40 /* Memory Timing Control IV */ +#define CHMCTRL_DECODE1 0x10 /* Memory Address Decode I */ +#define CHMCTRL_DECODE2 0x18 /* Memory Address Decode II */ +#define CHMCTRL_DECODE3 0x20 /* Memory Address Decode III */ +#define CHMCTRL_DECODE4 0x28 /* Memory Address Decode IV */ +#define CHMCTRL_MACTRL 0x30 /* Memory Address Control */ + +/* Memory Timing Control I */ +#define TCTRL1_SDRAMCTL_DLY 0xf000000000000000 +#define TCTRL1_SDRAMCTL_DLY_SHIFT 60 +#define TCTRL1_SDRAMCLK_DLY 0x0e00000000000000 +#define TCTRL1_SDRAMCLK_DLY_SHIFT 57 +#define TCTRL1_R 0x0100000000000000 +#define TCTRL1_R_SHIFT 56 +#define TCTRL1_AUTORFR_CYCLE 0x00fe000000000000 +#define TCTRL1_AUTORFR_CYCLE_SHIFT 49 +#define TCTRL1_RD_WAIT 0x0001f00000000000 +#define TCTRL1_RD_WAIT_SHIFT 44 +#define TCTRL1_PC_CYCLE 0x00000fc000000000 +#define TCTRL1_PC_CYCLE_SHIFT 38 +#define TCTRL1_WR_MORE_RAS_PW 0x0000003f00000000 +#define TCTRL1_WR_MORE_RAS_PW_SHIFT 32 +#define TCTRL1_RD_MORE_RAW_PW 0x00000000fc000000 +#define TCTRL1_RD_MORE_RAS_PW_SHIFT 26 +#define TCTRL1_ACT_WR_DLY 0x0000000003f00000 +#define TCTRL1_ACT_WR_DLY_SHIFT 20 +#define TCTRL1_ACT_RD_DLY 0x00000000000fc000 +#define TCTRL1_ACT_RD_DLY_SHIFT 14 +#define TCTRL1_BANK_PRESENT 0x0000000000003000 +#define TCTRL1_BANK_PRESENT_SHIFT 12 +#define TCTRL1_RFR_INT 0x0000000000000ff8 +#define TCTRL1_RFR_INT_SHIFT 3 +#define TCTRL1_SET_MODE_REG 0x0000000000000004 +#define TCTRL1_SET_MODE_REG_SHIFT 2 +#define TCTRL1_RFR_ENABLE 0x0000000000000002 +#define TCTRL1_RFR_ENABLE_SHIFT 1 +#define TCTRL1_PRECHG_ALL 0x0000000000000001 +#define TCTRL1_PRECHG_ALL_SHIFT 0 + +/* Memory Timing Control II */ +#define TCTRL2_WR_MSEL_DLY 0xfc00000000000000 +#define TCTRL2_WR_MSEL_DLY_SHIFT 58 +#define TCTRL2_RD_MSEL_DLY 0x03f0000000000000 +#define TCTRL2_RD_MSEL_DLY_SHIFT 52 +#define TCTRL2_WRDATA_THLD 0x000c000000000000 +#define TCTRL2_WRDATA_THLD_SHIFT 50 +#define TCTRL2_RDWR_RD_TI_DLY 0x0003f00000000000 +#define TCTRL2_RDWR_RD_TI_DLY_SHIFT 44 +#define TCTRL2_AUTOPRECHG_ENBL 0x0000080000000000 +#define TCTRL2_AUTOPRECHG_ENBL_SHIFT 43 +#define TCTRL2_RDWR_PI_MORE_DLY 0x000007c000000000 +#define TCTRL2_RDWR_PI_MORE_DLY_SHIFT 38 +#define TCTRL2_RDWR_1_DLY 0x0000003f00000000 +#define TCTRL2_RDWR_1_DLY_SHIFT 32 +#define TCTRL2_WRWR_PI_MORE_DLY 0x00000000f8000000 +#define TCTRL2_WRWR_PI_MORE_DLY_SHIFT 27 +#define TCTRL2_WRWR_1_DLY 0x0000000007e00000 +#define TCTRL2_WRWR_1_DLY_SHIFT 21 +#define TCTRL2_RDWR_RD_PI_MORE_DLY 0x00000000001f0000 +#define TCTRL2_RDWR_RD_PI_MORE_DLY_SHIFT 16 +#define TCTRL2_R 0x0000000000008000 +#define TCTRL2_R_SHIFT 15 +#define TCTRL2_SDRAM_MODE_REG_DATA 0x0000000000007fff +#define TCTRL2_SDRAM_MODE_REG_DATA_SHIFT 0 + +/* Memory Timing Control III */ +#define TCTRL3_SDRAM_CTL_DLY 0xf000000000000000 +#define TCTRL3_SDRAM_CTL_DLY_SHIFT 60 +#define TCTRL3_SDRAM_CLK_DLY 0x0e00000000000000 +#define TCTRL3_SDRAM_CLK_DLY_SHIFT 57 +#define TCTRL3_R 0x0100000000000000 +#define TCTRL3_R_SHIFT 56 +#define TCTRL3_AUTO_RFR_CYCLE 0x00fe000000000000 +#define TCTRL3_AUTO_RFR_CYCLE_SHIFT 49 +#define TCTRL3_RD_WAIT 0x0001f00000000000 +#define TCTRL3_RD_WAIT_SHIFT 44 +#define TCTRL3_PC_CYCLE 0x00000fc000000000 +#define TCTRL3_PC_CYCLE_SHIFT 38 +#define TCTRL3_WR_MORE_RAW_PW 0x0000003f00000000 +#define TCTRL3_WR_MORE_RAW_PW_SHIFT 32 +#define TCTRL3_RD_MORE_RAW_PW 0x00000000fc000000 +#define TCTRL3_RD_MORE_RAW_PW_SHIFT 26 +#define TCTRL3_ACT_WR_DLY 0x0000000003f00000 +#define TCTRL3_ACT_WR_DLY_SHIFT 20 +#define TCTRL3_ACT_RD_DLY 0x00000000000fc000 +#define TCTRL3_ACT_RD_DLY_SHIFT 14 +#define TCTRL3_BANK_PRESENT 0x0000000000003000 +#define TCTRL3_BANK_PRESENT_SHIFT 12 +#define TCTRL3_RFR_INT 0x0000000000000ff8 +#define TCTRL3_RFR_INT_SHIFT 3 +#define TCTRL3_SET_MODE_REG 0x0000000000000004 +#define TCTRL3_SET_MODE_REG_SHIFT 2 +#define TCTRL3_RFR_ENABLE 0x0000000000000002 +#define TCTRL3_RFR_ENABLE_SHIFT 1 +#define TCTRL3_PRECHG_ALL 0x0000000000000001 +#define TCTRL3_PRECHG_ALL_SHIFT 0 + +/* Memory Timing Control IV */ +#define TCTRL4_WR_MSEL_DLY 0xfc00000000000000 +#define TCTRL4_WR_MSEL_DLY_SHIFT 58 +#define TCTRL4_RD_MSEL_DLY 0x03f0000000000000 +#define TCTRL4_RD_MSEL_DLY_SHIFT 52 +#define TCTRL4_WRDATA_THLD 0x000c000000000000 +#define TCTRL4_WRDATA_THLD_SHIFT 50 +#define TCTRL4_RDWR_RD_RI_DLY 0x0003f00000000000 +#define TCTRL4_RDWR_RD_RI_DLY_SHIFT 44 +#define TCTRL4_AUTO_PRECHG_ENBL 0x0000080000000000 +#define TCTRL4_AUTO_PRECHG_ENBL_SHIFT 43 +#define TCTRL4_RD_WR_PI_MORE_DLY 0x000007c000000000 +#define TCTRL4_RD_WR_PI_MORE_DLY_SHIFT 38 +#define TCTRL4_RD_WR_TI_DLY 0x0000003f00000000 +#define TCTRL4_RD_WR_TI_DLY_SHIFT 32 +#define TCTRL4_WR_WR_PI_MORE_DLY 0x00000000f8000000 +#define TCTRL4_WR_WR_PI_MORE_DLY_SHIFT 27 +#define TCTRL4_WR_WR_TI_DLY 0x0000000007e00000 +#define TCTRL4_WR_WR_TI_DLY_SHIFT 21 +#define TCTRL4_RDWR_RD_PI_MORE_DLY 0x00000000001f0000 +#define TCTRL4_RDWR_RD_PI_MORE_DLY_SHIFT 16 +#define TCTRL4_R 0x0000000000008000 +#define TCTRL4_R_SHIFT 15 +#define TCTRL4_SDRAM_MODE_REG_DATA 0x0000000000007fff +#define TCTRL4_SDRAM_MODE_REG_DATA_SHIFT 0 + +/* All 4 memory address decoding registers have the + * same layout. + */ +#define MEM_DECODE_VALID 0x8000000000000000 /* Valid */ +#define MEM_DECODE_VALID_SHIFT 63 +#define MEM_DECODE_UK 0x001ffe0000000000 /* Upper mask */ +#define MEM_DECODE_UK_SHIFT 41 +#define MEM_DECODE_UM 0x0000001ffff00000 /* Upper match */ +#define MEM_DECODE_UM_SHIFT 20 +#define MEM_DECODE_LK 0x000000000003c000 /* Lower mask */ +#define MEM_DECODE_LK_SHIFT 14 +#define MEM_DECODE_LM 0x0000000000000f00 /* Lower match */ +#define MEM_DECODE_LM_SHIFT 8 + +#define PA_UPPER_BITS 0x000007fffc000000 +#define PA_UPPER_BITS_SHIFT 26 +#define PA_LOWER_BITS 0x00000000000003c0 +#define PA_LOWER_BITS_SHIFT 6 + +#define MACTRL_R0 0x8000000000000000 +#define MACTRL_R0_SHIFT 63 +#define MACTRL_ADDR_LE_PW 0x7000000000000000 +#define MACTRL_ADDR_LE_PW_SHIFT 60 +#define MACTRL_CMD_PW 0x0f00000000000000 +#define MACTRL_CMD_PW_SHIFT 56 +#define MACTRL_HALF_MODE_WR_MSEL_DLY 0x00fc000000000000 +#define MACTRL_HALF_MODE_WR_MSEL_DLY_SHIFT 50 +#define MACTRL_HALF_MODE_RD_MSEL_DLY 0x0003f00000000000 +#define MACTRL_HALF_MODE_RD_MSEL_DLY_SHIFT 44 +#define MACTRL_HALF_MODE_SDRAM_CTL_DLY 0x00000f0000000000 +#define MACTRL_HALF_MODE_SDRAM_CTL_DLY_SHIFT 40 +#define MACTRL_HALF_MODE_SDRAM_CLK_DLY 0x000000e000000000 +#define MACTRL_HALF_MODE_SDRAM_CLK_DLY_SHIFT 37 +#define MACTRL_R1 0x0000001000000000 +#define MACTRL_R1_SHIFT 36 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B3 0x0000000f00000000 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B3_SHIFT 32 +#define MACTRL_ENC_INTLV_B3 0x00000000f8000000 +#define MACTRL_ENC_INTLV_B3_SHIFT 27 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B2 0x0000000007800000 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B2_SHIFT 23 +#define MACTRL_ENC_INTLV_B2 0x00000000007c0000 +#define MACTRL_ENC_INTLV_B2_SHIFT 18 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B1 0x000000000003c000 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B1_SHIFT 14 +#define MACTRL_ENC_INTLV_B1 0x0000000000003e00 +#define MACTRL_ENC_INTLV_B1_SHIFT 9 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B0 0x00000000000001e0 +#define MACTRL_BANKSEL_N_ROWADDR_SIZE_B0_SHIFT 5 +#define MACTRL_ENC_INTLV_B0 0x000000000000001f +#define MACTRL_ENC_INTLV_B0_SHIFT 0 + +#endif /* _SPARC64_CHMCTRL_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h --- v2.4.3/linux/include/asm-sparc64/elf.h Mon Mar 26 11:00:29 2001 +++ linux/include/asm-sparc64/elf.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: elf.h,v 1.28 2001/03/24 09:36:02 davem Exp $ */ +/* $Id: elf.h,v 1.29 2001/03/30 07:10:48 davem Exp $ */ #ifndef __ASM_SPARC64_ELF_H #define __ASM_SPARC64_ELF_H diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/estate.h linux/include/asm-sparc64/estate.h --- v2.4.3/linux/include/asm-sparc64/estate.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/estate.h Thu Apr 12 12:10:25 2001 @@ -0,0 +1,50 @@ +/* $Id: estate.h,v 1.1 2001/03/28 10:56:34 davem Exp $ */ +#ifndef _SPARC64_ESTATE_H +#define _SPARC64_ESTATE_H + +/* UltraSPARC-III E-cache Error Enable */ +#define ESTATE_ERROR_FMT 0x0000000000040000 /* Force MTAG ECC */ +#define ESTATE_ERROR_FMESS 0x000000000003c000 /* Forced MTAG ECC val */ +#define ESTATE_ERROR_FMD 0x0000000000002000 /* Force DATA ECC */ +#define ESTATE_ERROR_FDECC 0x0000000000001ff0 /* Forced DATA ECC val */ +#define ESTATE_ERROR_UCEEN 0x0000000000000008 /* See below */ +#define ESTATE_ERROR_NCEEN 0x0000000000000002 /* See below */ +#define ESTATE_ERROR_CEEN 0x0000000000000001 /* See below */ + +/* UCEEN enables the fast_ECC_error trap for: 1) software correctable E-cache + * errors 2) uncorrectable E-cache errors. Such events only occur on reads + * of the E-cache by the local processor for: 1) data loads 2) instruction + * fetches 3) atomic operations. Such events _cannot_ occur for: 1) merge + * 2) writeback 2) copyout. The AFSR bits assosciated with these traps are + * UCC and UCU. + */ + +/* NCEEN enables instruction_access_error, data_access_error, and ECC_error traps + * for uncorrectable ECC errors and system errors. + * + * Uncorrectable system bus data error or MTAG ECC error, system bus TimeOUT, + * or system bus BusERR: + * 1) As the result of an instruction fetch, will generate instruction_access_error + * 2) As the result of a load etc. will generate data_access_error. + * 3) As the result of store merge completion, writeback, or copyout will + * generate a disrupting ECC_error trap. + * 4) As the result of such errors on instruction vector fetch can generate any + * of the 3 trap types. + * + * The AFSR bits assosciated with these traps are EMU, EDU, WDU, CPU, IVU, UE, + * BERR, and TO. + */ + +/* CEEN enables the ECC_error trap for hardware corrected ECC errors. System bus + * reads resulting in a hardware corrected data or MTAG ECC error will generate an + * ECC_error disrupting trap with this bit enabled. + * + * This same trap will also be generated when a hardware corrected ECC error results + * during store merge, writeback, and copyout operations. + */ + +/* In general, if the trap enable bits above are disabled the AFSR bits will still + * log the events even though the trap will not be generated by the processor. + */ + +#endif /* _SPARC64_ESTATE_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/mc146818rtc.h linux/include/asm-sparc64/mc146818rtc.h --- v2.4.3/linux/include/asm-sparc64/mc146818rtc.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc64/mc146818rtc.h Thu Apr 12 12:16:36 2001 @@ -4,6 +4,7 @@ #ifndef __ASM_SPARC64_MC146818RTC_H #define __ASM_SPARC64_MC146818RTC_H +#include <linux/config.h> #include <asm/io.h> #ifndef RTC_PORT diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/perfctr.h linux/include/asm-sparc64/perfctr.h --- v2.4.3/linux/include/asm-sparc64/perfctr.h Tue Oct 27 09:52:21 1998 +++ linux/include/asm-sparc64/perfctr.h Thu Apr 12 12:10:25 2001 @@ -60,10 +60,10 @@ #ifndef __KERNEL__ #define PRIV 0x00000001 -#define USR 0x00000002 -#define SYS 0x00000004 +#define SYS 0x00000002 +#define USR 0x00000004 -/* Pic.S0 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT 0x00000000 #define INSTR_CNT 0x00000010 #define DISPATCH0_IC_MISS 0x00000020 @@ -77,7 +77,38 @@ #define EC_SNOOP_INV 0x000000E0 #define EC_RD_HIT 0x000000F0 -/* Pic.S1 Selection Bit Field Encoding */ +/* Pic.S0 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT 0x00000000 +#define US3_INSTR_CNT 0x00000010 +#define US3_DISPATCH0_IC_MISS 0x00000020 +#define US3_DISPATCH0_BR_TGT 0x00000030 +#define US3_DISPATCH0_2ND_BR 0x00000040 +#define US3_RSTALL_STOREQ 0x00000050 +#define US3_RSTALL_IU_USE 0x00000060 +#define US3_IC_REF 0x00000080 +#define US3_DC_RD 0x00000090 +#define US3_DC_WR 0x000000a0 +#define US3_EC_REF 0x000000c0 +#define US3_EC_WR_HIT_RTO 0x000000d0 +#define US3_EC_SNOOP_INV 0x000000e0 +#define US3_EC_RD_MISS 0x000000f0 +#define US3_PC_PORT0_RD 0x00000100 +#define US3_SI_SNOOP 0x00000110 +#define US3_SI_CIQ_FLOW 0x00000120 +#define US3_SI_OWNED 0x00000130 +#define US3_SW_COUNT_0 0x00000140 +#define US3_IU_BR_MISS_TAKEN 0x00000150 +#define US3_IU_BR_COUNT_TAKEN 0x00000160 +#define US3_DISP_RS_MISPRED 0x00000170 +#define US3_FA_PIPE_COMPL 0x00000180 +#define US3_MC_READS_0 0x00000200 +#define US3_MC_READS_1 0x00000210 +#define US3_MC_READS_2 0x00000220 +#define US3_MC_READS_3 0x00000230 +#define US3_MC_STALLS_0 0x00000240 +#define US3_MC_STALLS_2 0x00000250 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II */ #define CYCLE_CNT_D1 0x00000000 #define INSTR_CNT_D1 0x00000800 #define DISPATCH0_IC_MISPRED 0x00001000 @@ -90,6 +121,47 @@ #define EC_WB 0x00006800 #define EC_SNOOP_CB 0x00007000 #define EC_IT_HIT 0x00007800 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT_D1 0x00000000 +#define US3_INSTR_CNT_D1 0x00000800 +#define US3_DISPATCH0_MISPRED 0x00001000 +#define US3_IC_MISS_CANCELLED 0x00001800 +#define US3_RE_ENDIAN_MISS 0x00002000 +#define US3_RE_FPU_BYPASS 0x00002800 +#define US3_RE_DC_MISS 0x00003000 +#define US3_RE_EC_MISS 0x00003800 +#define US3_IC_MISS 0x00004000 +#define US3_DC_RD_MISS 0x00004800 +#define US3_DC_WR_MISS 0x00005000 +#define US3_RSTALL_FP_USE 0x00005800 +#define US3_EC_MISSES 0x00006000 +#define US3_EC_WB 0x00006800 +#define US3_EC_SNOOP_CB 0x00007000 +#define US3_EC_IC_MISS 0x00007800 +#define US3_RE_PC_MISS 0x00008000 +#define US3_ITLB_MISS 0x00008800 +#define US3_DTLB_MISS 0x00009000 +#define US3_WC_MISS 0x00009800 +#define US3_WC_SNOOP_CB 0x0000a000 +#define US3_WC_SCRUBBED 0x0000a800 +#define US3_WC_WB_WO_READ 0x0000b000 +#define US3_PC_SOFT_HIT 0x0000c000 +#define US3_PC_SNOOP_INV 0x0000c800 +#define US3_PC_HARD_HIT 0x0000d000 +#define US3_PC_PORT1_RD 0x0000d800 +#define US3_SW_COUNT_1 0x0000e000 +#define US3_IU_STAT_BR_MIS_UNTAKEN 0x0000e800 +#define US3_IU_STAT_BR_COUNT_UNTAKEN 0x0000f000 +#define US3_PC_MS_MISSES 0x0000f800 +#define US3_MC_WRITES_0 0x00010800 +#define US3_MC_WRITES_1 0x00011000 +#define US3_MC_WRITES_2 0x00011800 +#define US3_MC_WRITES_3 0x00012000 +#define US3_MC_STALLS_1 0x00012800 +#define US3_MC_STALLS_3 0x00013000 +#define US3_RE_RAW_MISS 0x00013800 +#define US3_FM_PIPE_COMPLETION 0x00014000 struct vcounter_struct { unsigned long long vcnt0; diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h --- v2.4.3/linux/include/asm-sparc64/pgalloc.h Mon Mar 26 11:03:48 2001 +++ linux/include/asm-sparc64/pgalloc.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: pgalloc.h,v 1.18 2001/03/24 09:36:01 davem Exp $ */ +/* $Id: pgalloc.h,v 1.19 2001/03/30 07:10:48 davem Exp $ */ #ifndef _SPARC64_PGALLOC_H #define _SPARC64_PGALLOC_H diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.4.3/linux/include/asm-sparc64/pgtable.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc64/pgtable.h Fri Apr 13 20:15:55 2001 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.138 2001/03/08 09:55:56 davem Exp $ +/* $Id: pgtable.h,v 1.140 2001/04/12 22:41:15 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -254,12 +254,13 @@ } /* Encode and de-code a swap entry */ -#define SWP_TYPE(entry) (((entry).val >> PAGE_SHIFT) & 0xff) -#define SWP_OFFSET(entry) ((entry).val >> (PAGE_SHIFT + 8)) +#define SWP_TYPE(entry) (((entry).val >> PAGE_SHIFT) & 0xffUL) +#define SWP_OFFSET(entry) ((entry).val >> (PAGE_SHIFT + 8UL)) #define SWP_ENTRY(type, offset) \ ( (swp_entry_t) \ { \ - ((type << PAGE_SHIFT) | (offset << (PAGE_SHIFT + 8))) \ + (((long)(type) << PAGE_SHIFT) | \ + ((long)(offset) << (PAGE_SHIFT + 8UL))) \ } ) #define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define swp_entry_to_pte(x) ((pte_t) { (x).val }) @@ -302,9 +303,15 @@ #include <asm-generic/pgtable.h> -#endif /* !(__ASSEMBLY__) */ - /* We provide our own get_unmapped_area to cope with VA holes for userland */ #define HAVE_ARCH_UNMAPPED_AREA + +/* We provide a special get_unmapped_area for framebuffer mmaps to try and use + * the largest alignment possible such that larget PTEs can be used. + */ +extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long, unsigned long, unsigned long, unsigned long); +#define HAVE_ARCH_FB_UNMAPPED_AREA + +#endif /* !(__ASSEMBLY__) */ #endif /* !(_SPARC64_PGTABLE_H) */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h --- v2.4.3/linux/include/asm-sparc64/processor.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc64/processor.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.69 2001/03/08 22:08:51 davem Exp $ +/* $Id: processor.h,v 1.70 2001/03/27 02:36:38 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -79,7 +79,6 @@ #define SPARC_FLAG_32BIT 0x04 /* task is older 32-bit binary */ #define SPARC_FLAG_NEWCHILD 0x08 /* task is just-spawned child process */ #define SPARC_FLAG_PERFCTR 0x10 /* task has performance counters active */ -#define SPARC_FLAG_MMAPSHARED 0x20 /* task wants a shared mmap */ #define FAULT_CODE_WRITE 0x01 /* Write access, implies D-TLB */ #define FAULT_CODE_DTLB 0x02 /* Miss happened in D-TLB */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/rwsem.h linux/include/asm-sparc64/rwsem.h --- v2.4.3/linux/include/asm-sparc64/rwsem.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/rwsem.h Fri Apr 13 20:15:55 2001 @@ -0,0 +1,11 @@ +/* $Id: rwsem.h,v 1.1 2001/04/14 01:12:16 davem Exp $ */ +#ifndef _SPARC64_RWSEM_H +#define _SPARC64_RWSEM_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead +#endif + +#undef __HAVE_ARCH_SPECIFIC_RWSEM_IMPLEMENTATION + +#endif /* _SPARC64_RWSEM_H */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h --- v2.4.3/linux/include/asm-sparc64/semaphore.h Wed Jul 12 16:45:30 2000 +++ linux/include/asm-sparc64/semaphore.h Tue Apr 17 17:19:36 2001 @@ -8,6 +8,7 @@ #include <asm/bitops.h> #include <asm/system.h> #include <linux/wait.h> +#include <linux/rwsem.h> struct semaphore { atomic_t count; @@ -199,268 +200,6 @@ .previous\n" : : "r" (sem), "i" (__up) : "g5", "g7", "memory", "cc"); -} - -/* rw mutexes (should that be mutices? =) -- throw rw - * spinlocks and semaphores together, and this is what we - * end up with... - * - * The lock is initialized to BIAS. This way, a writer - * subtracts BIAS ands gets 0 for the case of an uncontended - * lock. Readers decrement by 1 and see a positive value - * when uncontended, negative if there are writers waiting - * (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and - * lots of processes. BIAS must be chosen such that subtracting - * BIAS once per CPU will result in the int remaining - * negative. - * In terms of fairness, this should result in the lock - * flopping back and forth between readers and writers - * under heavy use. - * - * -ben - * - * Once we start supporting machines with more than 128 CPUs, - * we should go for using a 64bit atomic type instead of 32bit - * as counter. We shall probably go for bias 0x80000000 then, - * so that single sethi can set it. - * - * -jj - */ -#define RW_LOCK_BIAS 0x01000000 -#define RW_LOCK_BIAS_STR "0x01000000" - -struct rw_semaphore { - int count; - /* So that this does not have to be 64bit type, - * we'll use le bitops on it which use casa instead of casx. - * bit 0 means read bias granted - * bit 1 means write bias granted - */ - unsigned granted; - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ -{ (count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RW_LOCK_BIAS; - sem->granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -extern void __down_read_failed(/* Special calling convention */ void); -extern void __down_write_failed(/* Special calling convention */ void); -extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers); - -extern inline void down_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - __asm__ __volatile__(" - 1: lduw [%0], %%g5 - subcc %%g5, 1, %%g7 - cas [%0], %%g5, %%g7 - bneg,pn %%icc, 3f - cmp %%g5, %%g7 - bne,pn %%icc, 1b - membar #StoreStore - 2: - .subsection 2 - 3: bne,pn %%icc, 1b - mov %0, %%g7 - save %%sp, -160, %%sp - mov %%g1, %%l1 - mov %%g2, %%l2 - call %1 - mov %%g3, %%l3 - mov %%l1, %%g1 - mov %%l2, %%g2 - ba,pt %%xcc, 2b - restore %%l3, %%g0, %%g3 - .previous\n" - : : "r" (sem), "i" (__down_read_failed) - : "g5", "g7", "memory", "cc"); -#if WAITQUEUE_DEBUG - if (test_le_bit(1, &sem->granted)) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - __asm__ __volatile__(" - 1: lduw [%0], %%g5 - sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 - subcc %%g5, %%g7, %%g7 - cas [%0], %%g5, %%g7 - bne,pn %%icc, 3f - cmp %%g5, %%g7 - bne,pn %%icc, 1b - membar #StoreStore - 2: - .subsection 2 - 3: bne,pn %%icc, 1b - mov %0, %%g7 - save %%sp, -160, %%sp - mov %%g1, %%l1 - mov %%g2, %%l2 - call %1 - mov %%g3, %%l3 - mov %%l1, %%g1 - mov %%l2, %%g2 - ba,pt %%xcc, 2b - restore %%l3, %%g0, %%g3 - .previous\n" - : : "r" (sem), "i" (__down_write_failed) - : "g5", "g7", "memory", "cc"); -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (test_le_bit(0, &sem->granted)) - BUG(); - if (test_le_bit(1, &sem->granted)) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant - * case is when there was a writer waiting, and we've - * bumped the count to 0: we must wake the writer up. - */ -extern inline void __up_read(struct rw_semaphore *sem) -{ - __asm__ __volatile__(" - membar #StoreLoad | #LoadLoad - 1: lduw [%0], %%g5 - addcc %%g5, 1, %%g7 - cas [%0], %%g5, %%g7 - be,pn %%icc, 3f - cmp %%g5, %%g7 - bne,pn %%icc, 1b - nop - 2: - .subsection 2 - 3: bne,pn %%icc, 1b - mov %0, %%g7 - save %%sp, -160, %%sp - mov %%g1, %%l1 - mov %%g2, %%l2 - clr %%o1 - mov %%g7, %%o0 - call %1 - mov %%g3, %%l3 - mov %%l1, %%g1 - mov %%l2, %%g2 - ba,pt %%xcc, 2b - restore %%l3, %%g0, %%g3 - .previous\n" - : : "r" (sem), "i" (__rwsem_wake) - : "g5", "g7", "memory", "cc"); -} - -/* releasing the writer is easy -- just release it and - * wake up any sleepers. - */ -extern inline void __up_write(struct rw_semaphore *sem) -{ - __asm__ __volatile__(" - membar #StoreLoad | #LoadLoad - 1: lduw [%0], %%g5 - sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 - add %%g5, %%g7, %%g7 - cas [%0], %%g5, %%g7 - cmp %%g5, %%g7 - bne,pn %%icc, 1b - sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 - addcc %%g5, %%g7, %%g5 - bcs,pn %%icc, 3f - nop - 2: - .subsection 2 - 3: mov %0, %%g7 - save %%sp, -160, %%sp - mov %%g1, %%l1 - mov %%g2, %%l2 - srl %%g5, 0, %%o1 - mov %%g7, %%o0 - call %1 - mov %%g3, %%l3 - mov %%l1, %%g1 - mov %%l2, %%g2 - ba,pt %%xcc, 2b - restore %%l3, %%g0, %%g3 - .previous\n" - : : "r" (sem), "i" (__rwsem_wake) - : "g5", "g7", "memory", "cc"); -} - -extern inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (test_le_bit(1, &sem->granted)) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - __up_read(sem); -} - -extern inline void up_write(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - if (test_le_bit(0, &sem->granted)) - BUG(); - if (test_le_bit(1, &sem->granted)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - __up_write(sem); } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h --- v2.4.3/linux/include/asm-sparc64/spitfire.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc64/spitfire.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: spitfire.h,v 1.14 2001/03/22 07:26:04 davem Exp $ +/* $Id: spitfire.h,v 1.15 2001/03/27 00:10:15 davem Exp $ * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -13,10 +13,15 @@ * and ASI_IMMU, that is there is a distinct and unique copy of * each these registers for each TLB. */ -#define TSB_TAG_TARGET 0x0000000000000000 -#define TLB_SFSR 0x0000000000000018 -#define TSB_REG 0x0000000000000028 -#define TLB_TAG_ACCESS 0x0000000000000030 +#define TSB_TAG_TARGET 0x0000000000000000 /* All chips */ +#define TLB_SFSR 0x0000000000000018 /* All chips */ +#define TSB_REG 0x0000000000000028 /* All chips */ +#define TLB_TAG_ACCESS 0x0000000000000030 /* All chips */ +#define VIRT_WATCHPOINT 0x0000000000000038 /* All chips */ +#define PHYS_WATCHPOINT 0x0000000000000040 /* All chips */ +#define TSB_EXTENSION_P 0x0000000000000048 /* Ultra-III and later */ +#define TSB_EXTENSION_S 0x0000000000000050 /* Ultra-III and later, D-TLB only */ +#define TSB_EXTENSION_N 0x0000000000000058 /* Ultra-III and later */ /* These registers only exist as one entity, and are accessed * via ASI_DMMU only. diff -u --recursive --new-file v2.4.3/linux/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h --- v2.4.3/linux/include/asm-sparc64/ttable.h Wed Apr 12 09:12:35 2000 +++ linux/include/asm-sparc64/ttable.h Thu Apr 12 12:10:25 2001 @@ -1,4 +1,4 @@ -/* $Id: ttable.h,v 1.15 2000/04/03 10:36:42 davem Exp $ */ +/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */ #ifndef _SPARC64_TTABLE_H #define _SPARC64_TTABLE_H @@ -54,13 +54,6 @@ clr %l6; \ nop; -#define TRAPTL1_CEE \ - ldxa [%g0] ASI_AFSR, %g1; \ - membar #Sync; \ - stxa %g1, [%g0] ASI_AFSR; \ - membar #Sync; \ - retry; nop; nop; nop; - #define TRAP_ARG(routine, arg) \ sethi %hi(109f), %g7; \ ba,pt %xcc, etrap; \ diff -u --recursive --new-file v2.4.3/linux/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h --- v2.4.3/linux/include/linux/ac97_codec.h Mon Mar 26 15:49:49 2001 +++ linux/include/linux/ac97_codec.h Tue Apr 17 14:44:28 2001 @@ -133,7 +133,15 @@ SOUND_MASK_LINE1| SOUND_MASK_LINE|\ SOUND_MASK_PHONEIN) -#define supported_mixer(CODEC,FOO) ((CODEC)->supported_mixers & (1<<FOO) ) +/* original check is not good enough in case FOO is greater than + * SOUND_MIXER_NRDEVICES because the supported_mixers has exactly + * SOUND_MIXER_NRDEVICES elements. + * before matching the given mixer against the bitmask in supported_mixers we + * check if mixer number exceeds maximum allowed size which is as mentioned + * above SOUND_MIXER_NRDEVICES */ +#define supported_mixer(CODEC,FOO) ((FOO >= 0) && \ + (FOO < SOUND_MIXER_NRDEVICES) && \ + (CODEC)->supported_mixers & (1<<FOO) ) struct ac97_codec { /* AC97 controller connected with */ diff -u --recursive --new-file v2.4.3/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v2.4.3/linux/include/linux/apm_bios.h Wed Dec 6 21:00:13 2000 +++ linux/include/linux/apm_bios.h Fri Apr 6 10:51:19 2001 @@ -3,7 +3,7 @@ /* * Include file for the interface to an APM BIOS - * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * 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 diff -u --recursive --new-file v2.4.3/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.4.3/linux/include/linux/blk.h Mon Mar 26 15:48:46 2001 +++ linux/include/linux/blk.h Tue Apr 17 14:44:27 2001 @@ -42,7 +42,6 @@ extern int swimiop_init(void); extern int amiga_floppy_init(void); extern int atari_floppy_init(void); -extern int nbd_init(void); extern int ez_init(void); extern int bpcd_init(void); extern int ps2esdi_init(void); @@ -51,6 +50,7 @@ #if defined(CONFIG_ARCH_S390) extern int mdisk_init(void); extern int dasd_init(void); +extern int xpram_init(void); #endif /* CONFIG_ARCH_S390 */ extern void set_device_ro(kdev_t dev,int flag); diff -u --recursive --new-file v2.4.3/linux/include/linux/blkdev.h linux/include/linux/blkdev.h --- v2.4.3/linux/include/linux/blkdev.h Mon Mar 26 15:48:13 2001 +++ linux/include/linux/blkdev.h Tue Apr 17 14:44:18 2001 @@ -161,7 +161,6 @@ extern void blk_init_queue(request_queue_t *, request_fn_proc *); extern void blk_cleanup_queue(request_queue_t *); extern void blk_queue_headactive(request_queue_t *, int); -extern void blk_queue_pluggable(request_queue_t *, plug_device_fn *); extern void blk_queue_make_request(request_queue_t *, make_request_fn *); extern void generic_unplug_device(void *); diff -u --recursive --new-file v2.4.3/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v2.4.3/linux/include/linux/cdrom.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/cdrom.h Tue Apr 17 14:44:29 2001 @@ -128,8 +128,13 @@ #define CDROM_DEBUG 0x5330 /* Turn debug messages on/off */ #define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ +/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386. + * Future CDROM ioctls should be kept below 0x537F + */ + /* This ioctl is only used by sbpcd at the moment */ #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ + /* conflict with SCSI_IOCTL_GET_IDLUN */ /* DVD-ROM Specific ioctls */ #define DVD_READ_STRUCT 0x5390 /* Read structure */ diff -u --recursive --new-file v2.4.3/linux/include/linux/coff.h linux/include/linux/coff.h --- v2.4.3/linux/include/linux/coff.h Wed Aug 10 09:26:42 1994 +++ linux/include/linux/coff.h Fri Apr 6 10:51:19 2001 @@ -1,5 +1,5 @@ /* This file is derived from the GAS 2.1.4 assembler control file. - The GAS product is under the GNU Public License, version 2 or later. + The GAS product is under the GNU General Public License, version 2 or later. As such, this file is also under that license. If the file format changes in the COFF object, this file should be diff -u --recursive --new-file v2.4.3/linux/include/linux/com20020.h linux/include/linux/com20020.h --- v2.4.3/linux/include/linux/com20020.h Tue May 2 12:36:09 2000 +++ linux/include/linux/com20020.h Fri Apr 6 10:51:19 2001 @@ -15,7 +15,7 @@ * skeleton.c Written 1993 by Donald Becker. * Copyright 1993 United States Government as represented by the * Director, National Security Agency. This software may only be used - * and distributed according to the terms of the GNU Public License as + * and distributed according to the terms of the GNU General Public License as * modified by SRC, incorporated herein by reference. * * ********************** diff -u --recursive --new-file v2.4.3/linux/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h --- v2.4.3/linux/include/linux/devfs_fs_kernel.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/devfs_fs_kernel.h Tue Apr 17 15:04:11 2001 @@ -96,7 +96,6 @@ unsigned int minor_start, umode_t mode, void *ops, void *info); -extern int init_devfs_fs (void); extern void mount_devfs_fs (void); extern void devfs_make_root (const char *name); #else /* CONFIG_DEVFS_FS */ @@ -233,10 +232,6 @@ return; } -static inline int init_devfs_fs (void) -{ - return 0; -} static inline void mount_devfs_fs (void) { return; diff -u --recursive --new-file v2.4.3/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.3/linux/include/linux/fs.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/fs.h Tue Apr 17 14:43:46 2001 @@ -774,6 +774,8 @@ int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); + ssize_t (*writepage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; struct inode_operations { @@ -1225,6 +1227,7 @@ } return inode; } +extern void remove_suid(struct inode *inode); extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); @@ -1272,6 +1275,7 @@ int block_truncate_page(struct address_space *, loff_t, get_block_t *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); +extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *); extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); @@ -1291,7 +1295,6 @@ extern struct file_system_type *get_fs_type(const char *name); extern struct super_block *get_super(kdev_t); -struct super_block *get_empty_super(void); extern void put_super(kdev_t); unsigned long generate_cluster(kdev_t, int b[], int); unsigned long generate_cluster_swab32(kdev_t, int b[], int); diff -u --recursive --new-file v2.4.3/linux/include/linux/icmp.h linux/include/linux/icmp.h --- v2.4.3/linux/include/linux/icmp.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/icmp.h Thu Apr 12 12:11:39 2001 @@ -80,30 +80,6 @@ } un; }; -#ifdef __KERNEL__ - -#include <linux/ip.h> - -/* - * Build xmit assembly blocks - */ - -struct icmp_bxm -{ - void *data_ptr; - int data_len; - struct icmphdr icmph; - unsigned long csum; - struct ip_options replyopts; - unsigned char optbuf[40]; -}; - -struct sk_buff; - -extern void icmp_reply(struct icmp_bxm *, struct sk_buff *); - -#endif - /* * constants for (set|get)sockopt */ diff -u --recursive --new-file v2.4.3/linux/include/linux/icmpv6.h linux/include/linux/icmpv6.h --- v2.4.3/linux/include/linux/icmpv6.h Mon Mar 26 15:48:19 2001 +++ linux/include/linux/icmpv6.h Tue Apr 17 14:44:54 2001 @@ -143,7 +143,7 @@ int *err); extern void icmpv6_cleanup(void); extern void icmpv6_param_prob(struct sk_buff *skb, - int code, void *pos); + int code, int pos); #endif #endif diff -u --recursive --new-file v2.4.3/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.4.3/linux/include/linux/if_arp.h Mon Mar 26 15:48:19 2001 +++ linux/include/linux/if_arp.h Tue Apr 17 14:44:11 2001 @@ -73,7 +73,7 @@ #define ARPHRD_ECONET 782 /* Acorn Econet */ #define ARPHRD_IRDA 783 /* Linux-IrDA */ /* ARP works differently on different FC media .. so */ -#define ARPHRD_FCPP 784 /* Point to point fibrechanel */ +#define ARPHRD_FCPP 784 /* Point to point fibrechannel */ #define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ #define ARPHRD_FCPL 786 /* Fibrechannel public loop */ #define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ diff -u --recursive --new-file v2.4.3/linux/include/linux/if_packet.h linux/include/linux/if_packet.h --- v2.4.3/linux/include/linux/if_packet.h Thu Aug 10 13:01:26 2000 +++ linux/include/linux/if_packet.h Thu Apr 12 12:11:39 2001 @@ -53,6 +53,7 @@ #define TP_STATUS_USER 1 #define TP_STATUS_COPY 2 #define TP_STATUS_LOSING 4 +#define TP_STATUS_CSUMNOTREADY 8 unsigned int tp_len; unsigned int tp_snaplen; unsigned short tp_mac; diff -u --recursive --new-file v2.4.3/linux/include/linux/if_wanpipe.h linux/include/linux/if_wanpipe.h --- v2.4.3/linux/include/linux/if_wanpipe.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_wanpipe.h Tue Apr 17 14:43:29 2001 @@ -0,0 +1,128 @@ +/***************************************************************************** +* if_wanpipe.h Header file for the Sangoma AF_WANPIPE Socket +* +* Author: Nenad Corbic +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* +* Jan 28, 2000 Nenad Corbic Initial Version +* +*****************************************************************************/ + +#ifndef __LINUX_IF_WAN_PACKET_H +#define __LINUX_IF_WAN_PACKET_H + +struct wan_sockaddr_ll +{ + unsigned short sll_family; + unsigned short sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; + unsigned char sll_device[14]; + unsigned char sll_card[14]; +}; + +typedef struct +{ + unsigned char free; + unsigned char sk_state; + int rcvbuf; + int sndbuf; + int rmem; + int wmem; + int sk_count; + unsigned char bound; + char name[14]; + unsigned char d_state; + unsigned char svc; + unsigned short lcn; + unsigned char mbox; + unsigned char cmd_busy; + unsigned char command; + unsigned poll; + unsigned poll_cnt; + int rblock; +} wan_debug_hdr_t; + +#define MAX_NUM_DEBUG 10 +#define X25_PROT 0x16 +#define PVC_PROT 0x17 + +typedef struct +{ + wan_debug_hdr_t debug[MAX_NUM_DEBUG]; +}wan_debug_t; + +#define SIOC_WANPIPE_GET_CALL_DATA (SIOCPROTOPRIVATE + 0) +#define SIOC_WANPIPE_SET_CALL_DATA (SIOCPROTOPRIVATE + 1) +#define SIOC_WANPIPE_ACCEPT_CALL (SIOCPROTOPRIVATE + 2) +#define SIOC_WANPIPE_CLEAR_CALL (SIOCPROTOPRIVATE + 3) +#define SIOC_WANPIPE_RESET_CALL (SIOCPROTOPRIVATE + 4) +#define SIOC_WANPIPE_DEBUG (SIOCPROTOPRIVATE + 5) +#define SIOC_WANPIPE_SET_NONBLOCK (SIOCPROTOPRIVATE + 6) +#define SIOC_WANPIPE_CHECK_TX (SIOCPROTOPRIVATE + 7) +#define SIOC_WANPIPE_SOCK_STATE (SIOCPROTOPRIVATE + 8) + +/* Packet types */ + +#define WAN_PACKET_HOST 0 /* To us */ +#define WAN_PACKET_BROADCAST 1 /* To all */ +#define WAN_PACKET_MULTICAST 2 /* To group */ +#define WAN_PACKET_OTHERHOST 3 /* To someone else */ +#define WAN_PACKET_OUTGOING 4 /* Outgoing of any type */ +/* These ones are invisible by user level */ +#define WAN_PACKET_LOOPBACK 5 /* MC/BRD frame looped back */ +#define WAN_PACKET_FASTROUTE 6 /* Fastrouted frame */ + + +/* X25 specific */ +#define WAN_PACKET_DATA 7 +#define WAN_PACKET_CMD 8 +#define WAN_PACKET_ASYNC 9 +#define WAN_PACKET_ERR 10 + +/* Packet socket options */ + +#define WAN_PACKET_ADD_MEMBERSHIP 1 +#define WAN_PACKET_DROP_MEMBERSHIP 2 + +#define WAN_PACKET_MR_MULTICAST 0 +#define WAN_PACKET_MR_PROMISC 1 +#define WAN_PACKET_MR_ALLMULTI 2 + +#ifdef __KERNEL__ +#ifndef netdevice_t +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define netdevice_t struct net_device +#else + #define netdevice_t struct device +#endif +#endif + +/* Private wanpipe socket structures. */ +struct wanpipe_opt +{ + void *mbox; /* Mail box */ + void *card; /* Card bouded to */ + netdevice_t *dev; /* Bounded device */ + unsigned short lcn; /* Binded LCN */ + unsigned char svc; /* 0=pvc, 1=svc */ + unsigned char timer; /* flag for delayed transmit*/ + struct timer_list tx_timer; + unsigned poll_cnt; + unsigned char force; /* Used to force sock release */ + atomic_t packet_sent; +}; +#endif + +#endif diff -u --recursive --new-file v2.4.3/linux/include/linux/if_wanpipe_common.h linux/include/linux/if_wanpipe_common.h --- v2.4.3/linux/include/linux/if_wanpipe_common.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_wanpipe_common.h Thu Apr 12 12:11:39 2001 @@ -0,0 +1,67 @@ +/***************************************************************************** +* if_wanipe_common.h Sangoma Driver/Socket common area definitions. +* +* Author: Nenad Corbic <ncorbic@sangoma.com> +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Jan 13, 2000 Nenad Corbic Initial version +*****************************************************************************/ + + +#ifndef _WANPIPE_SOCK_DRIVER_COMMON_H +#define _WANPIPE_SOCK_DRIVER_COMMON_H + +#include <linux/version.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define netdevice_t struct net_device +#else + #define netdevice_t struct device +#endif + + +typedef struct { + netdevice_t *slave; + atomic_t packet_sent; + atomic_t receive_block; + atomic_t command; + atomic_t disconnect; + atomic_t driver_busy; + unsigned char common_critical; + struct timer_list *tx_timer; + struct sock *sk; /* Wanpipe Sock bind's here */ + int (*func) (struct sk_buff *, netdevice_t *, + struct sock *); + + struct tq_struct wanpipe_task; /* Immediate BH handler task */ + unsigned char rw_bind; /* Sock bind state */ + unsigned char usedby; + unsigned char state; + unsigned char svc; + unsigned short lcn; + void *mbox; +} wanpipe_common_t; + + +enum { + WANSOCK_UNCONFIGURED, /* link/channel is not configured */ + WANSOCK_DISCONNECTED, /* link/channel is disconnected */ + WANSOCK_CONNECTING, /* connection is in progress */ + WANSOCK_CONNECTED, /* link/channel is operational */ + WANSOCK_LIMIT, /* for verification only */ + WANSOCK_DUALPORT, /* for Dual Port cards */ + WANSOCK_DISCONNECTING, + WANSOCK_BINDED, + WANSOCK_BIND_LISTEN, + WANSOCK_LISTEN +}; + +#endif + + diff -u --recursive --new-file v2.4.3/linux/include/linux/igmp.h linux/include/linux/igmp.h --- v2.4.3/linux/include/linux/igmp.h Mon Aug 23 10:01:02 1999 +++ linux/include/linux/igmp.h Thu Apr 12 12:11:39 2001 @@ -104,7 +104,7 @@ }; extern int ip_check_mc(struct in_device *dev, u32 mc_addr); -extern int igmp_rcv(struct sk_buff *, unsigned short); +extern int igmp_rcv(struct sk_buff *); extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); extern void ip_mc_drop_socket(struct sock *sk); diff -u --recursive --new-file v2.4.3/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v2.4.3/linux/include/linux/isdn.h Fri Feb 9 11:29:44 2001 +++ linux/include/linux/isdn.h Thu Apr 12 12:20:31 2001 @@ -37,14 +37,8 @@ * the correspondent code in isdn.c */ -#ifdef CONFIG_COBALT_MICRO_SERVER -/* Save memory */ -#define ISDN_MAX_DRIVERS 2 -#define ISDN_MAX_CHANNELS 8 -#else #define ISDN_MAX_DRIVERS 32 #define ISDN_MAX_CHANNELS 64 -#endif #define ISDN_MINOR_B 0 #define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1) #define ISDN_MINOR_CTRL 64 @@ -420,7 +414,7 @@ struct net_device dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP ippp_bundle * pb; /* pointer to the common bundle structure - * with the the per-bundle data */ + * with the per-bundle data */ #endif #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot; /* connection oriented encapsulation protocol */ diff -u --recursive --new-file v2.4.3/linux/include/linux/joystick.h linux/include/linux/joystick.h --- v2.4.3/linux/include/linux/joystick.h Wed Jun 21 08:22:21 2000 +++ linux/include/linux/joystick.h Wed Apr 11 19:02:30 2001 @@ -2,7 +2,7 @@ #define _LINUX_JOYSTICK_H /* - * $Id: joystick.h,v 1.2 2000/05/29 10:54:53 vojtech Exp $ + * $Id: joystick.h,v 1.3 2000/11/30 11:07:05 vojtech Exp $ * * Copyright (C) 1996-2000 Vojtech Pavlik * @@ -30,12 +30,13 @@ */ #include <asm/types.h> +#include <linux/input.h> /* * Version */ -#define JS_VERSION 0x020000 +#define JS_VERSION 0x020100 /* * Types and constants for reading from /dev/js @@ -46,7 +47,7 @@ #define JS_EVENT_INIT 0x80 /* initial state of device */ struct js_event { - __u32 time; /* event timestamp in miliseconds */ + __u32 time; /* event timestamp in milliseconds */ __s16 value; /* value */ __u8 type; /* event type */ __u8 number; /* axis/button number */ @@ -56,14 +57,19 @@ * IOCTL commands for joystick driver */ -#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ +#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ -#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ -#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ -#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */ - -#define JSIOCSCORR _IOW('j', 0x21, struct js_corr) /* set correction values */ -#define JSIOCGCORR _IOR('j', 0x22, struct js_corr) /* get correction values */ +#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ +#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ +#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */ + +#define JSIOCSCORR _IOW('j', 0x21, struct js_corr) /* set correction values */ +#define JSIOCGCORR _IOR('j', 0x22, struct js_corr) /* get correction values */ + +#define JSIOCSAXMAP _IOW('j', 0x31, __u8[ABS_MAX]) /* set axis mapping */ +#define JSIOCGAXMAP _IOR('j', 0x32, __u8[ABS_MAX]) /* get axis mapping */ +#define JSIOCSBTNMAP _IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC]) /* set button mapping */ +#define JSIOCGBTNMAP _IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC]) /* get button mapping */ /* * Types and constants for get/set correction diff -u --recursive --new-file v2.4.3/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.4.3/linux/include/linux/kernel.h Mon Dec 11 12:49:54 2000 +++ linux/include/linux/kernel.h Thu Apr 12 12:25:53 2001 @@ -62,7 +62,7 @@ extern int vsprintf(char *buf, const char *, va_list); extern int get_option(char **str, int *pint); extern char *get_options(char *str, int nints, int *ints); -extern unsigned long memparse(char *ptr, char **retptr); +extern unsigned long long memparse(char *ptr, char **retptr); extern void dev_probe_lock(void); extern void dev_probe_unlock(void); diff -u --recursive --new-file v2.4.3/linux/include/linux/major.h linux/include/linux/major.h --- v2.4.3/linux/include/linux/major.h Sat Dec 30 11:23:14 2000 +++ linux/include/linux/major.h Thu Apr 12 12:20:31 2001 @@ -128,6 +128,8 @@ #define IDE8_MAJOR 90 #define IDE9_MAJOR 91 +#define UBD_MAJOR 98 + #define AURORA_MAJOR 79 #define JSFD_MAJOR 99 @@ -155,6 +157,9 @@ #define CPUID_MAJOR 203 #define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ + +#define IBM_TTY3270_MAJOR 227 /* Official allocations now */ +#define IBM_FS3270_MAJOR 228 /* * Tests for SCSI devices. diff -u --recursive --new-file v2.4.3/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h --- v2.4.3/linux/include/linux/miscdevice.h Mon Mar 26 15:48:22 2001 +++ linux/include/linux/miscdevice.h Tue Apr 17 14:45:16 2001 @@ -21,6 +21,7 @@ #define NVRAM_MINOR 144 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 +#define MPT_MINOR 220 #define MISC_DYNAMIC_MINOR 255 #define SGI_GRAPHICS_MINOR 146 diff -u --recursive --new-file v2.4.3/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.3/linux/include/linux/mm.h Mon Mar 26 15:48:13 2001 +++ linux/include/linux/mm.h Tue Apr 17 14:43:52 2001 @@ -434,7 +434,8 @@ extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void build_mmap_avl(struct mm_struct *); extern void exit_mmap(struct mm_struct *); -extern unsigned long get_unmapped_area(unsigned long, unsigned long); + +extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, diff -u --recursive --new-file v2.4.3/linux/include/linux/mroute.h linux/include/linux/mroute.h --- v2.4.3/linux/include/linux/mroute.h Mon Mar 26 15:48:59 2001 +++ linux/include/linux/mroute.h Tue Apr 17 14:43:50 2001 @@ -215,8 +215,8 @@ __u32 flags; }; -extern int pim_rcv(struct sk_buff * , unsigned short); -extern int pim_rcv_v1(struct sk_buff * , unsigned short len); +extern int pim_rcv(struct sk_buff *); +extern int pim_rcv_v1(struct sk_buff *); struct rtmsg; extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); diff -u --recursive --new-file v2.4.3/linux/include/linux/nbd.h linux/include/linux/nbd.h --- v2.4.3/linux/include/linux/nbd.h Mon Dec 11 12:50:42 2000 +++ linux/include/linux/nbd.h Wed Apr 11 19:02:30 2001 @@ -31,35 +31,27 @@ extern int requests_out; #endif -static int +static void nbd_end_request(struct request *req) { + struct buffer_head *bh; + unsigned nsect; unsigned long flags; - int ret = 0; + int uptodate = (req->errors == 0) ? 1 : 0; #ifdef PARANOIA requests_out++; #endif - /* - * This is a very dirty hack that we have to do to handle - * merged requests because end_request stuff is a bit - * broken. The fact we have to do this only if there - * aren't errors looks even more silly. - */ - if (!req->errors) { - req->sector += req->current_nr_sectors; - req->nr_sectors -= req->current_nr_sectors; - } - spin_lock_irqsave(&io_request_lock, flags); - if (end_that_request_first( req, !req->errors, "nbd" )) - goto out; - ret = 1; - end_that_request_last( req ); - -out: + while((bh = req->bh) != NULL) { + nsect = bh->b_size >> 9; + blk_finished_io(nsect); + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, uptodate); + } + blkdev_release_request(req); spin_unlock_irqrestore(&io_request_lock, flags); - return ret; } #define MAX_NBD 128 diff -u --recursive --new-file v2.4.3/linux/include/linux/net.h linux/include/linux/net.h --- v2.4.3/linux/include/linux/net.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/net.h Tue Apr 17 14:43:40 2001 @@ -82,6 +82,7 @@ struct scm_cookie; struct vm_area_struct; +struct page; struct proto_ops { int family; @@ -108,6 +109,7 @@ int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm); int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm); int (*mmap) (struct file *file, struct socket *sock, struct vm_area_struct * vma); + ssize_t (*sendpage) (struct socket *sock, struct page *page, int offset, size_t size, int flags); }; struct net_proto_family diff -u --recursive --new-file v2.4.3/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.4.3/linux/include/linux/netdevice.h Mon Mar 26 15:48:19 2001 +++ linux/include/linux/netdevice.h Tue Apr 17 14:44:10 2001 @@ -653,6 +653,7 @@ extern unsigned long netdev_fc_xoff; extern atomic_t netdev_dropping; extern int netdev_set_master(struct net_device *dev, struct net_device *master); +extern struct sk_buff * skb_checksum_help(struct sk_buff *skb); #ifdef CONFIG_NET_FASTROUTE extern int netdev_fastroute; extern int netdev_fastroute_obstacles; diff -u --recursive --new-file v2.4.3/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.4.3/linux/include/linux/nfs_fs.h Mon Mar 26 15:48:42 2001 +++ linux/include/linux/nfs_fs.h Tue Apr 17 15:04:11 2001 @@ -137,7 +137,6 @@ * linux/fs/nfs/inode.c */ extern struct super_block *nfs_read_super(struct super_block *, void *, int); -extern int init_nfs_fs(void); extern void nfs_zap_caches(struct inode *); extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *, struct nfs_fattr *); diff -u --recursive --new-file v2.4.3/linux/include/linux/rwsem-spinlock.h linux/include/linux/rwsem-spinlock.h --- v2.4.3/linux/include/linux/rwsem-spinlock.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/rwsem-spinlock.h Tue Apr 17 17:19:36 2001 @@ -0,0 +1,172 @@ +/* rwsem-spinlock.h: fallback C implementation + * + * Copyright (c) 2001 David Howells (dhowells@redhat.com). + */ + +#ifndef _LINUX_RWSEM_SPINLOCK_H +#define _LINUX_RWSEM_SPINLOCK_H + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem-spinlock.h directly, use linux/rwsem.h instead +#endif + +#include <linux/spinlock.h> + +#ifdef __KERNEL__ + +/* + * the semaphore definition + */ +struct rw_semaphore { + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t lock; +#define RWSEM_SPINLOCK_OFFSET_STR "4" /* byte offset of spinlock */ + wait_queue_head_t wait; +#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0 /* bits to use in wait_queue_t.flags */ +#define RWSEM_WAITING_FOR_WRITE WQ_FLAG_CONTEXT_1 +#if RWSEM_DEBUG + int debug; +#endif +#if RWSEM_DEBUG_MAGIC + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +/* + * initialisation + */ +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif +#if RWSEM_DEBUG_MAGIC +#define __RWSEM_DEBUG_MINIT(name) , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_MINIT(name) /* */ +#endif + +#define __RWSEM_INITIALIZER(name,count) \ +{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) } + +#define __DECLARE_RWSEM_GENERIC(name,count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) + +#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->lock); + init_waitqueue_head(&sem->wait); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +#if RWSEM_DEBUG_MAGIC + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + sem->count += RWSEM_ACTIVE_READ_BIAS; + count = sem->count; + spin_unlock(&sem->lock); + if (count<0) + rwsem_down_read_failed(sem); +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + count = sem->count; + sem->count += RWSEM_ACTIVE_WRITE_BIAS; + spin_unlock(&sem->lock); + if (count) + rwsem_down_write_failed(sem); +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + count = sem->count; + sem->count -= RWSEM_ACTIVE_READ_BIAS; + spin_unlock(&sem->lock); + if (count<0 && !((count-RWSEM_ACTIVE_READ_BIAS)&RWSEM_ACTIVE_MASK)) + rwsem_wake(sem); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + int count; + spin_lock(&sem->lock); + sem->count -= RWSEM_ACTIVE_WRITE_BIAS; + count = sem->count; + spin_unlock(&sem->lock); + if (count<0) + rwsem_wake(sem); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + int count; + + spin_lock(&sem->lock); + sem->count += delta; + count = sem->count; + spin_unlock(&sem->lock); + + return count; +} + +/* + * implement compare and exchange functionality on the rw-semaphore count LSW + */ +static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new) +{ + __u16 prev; + + spin_lock(&sem->lock); + prev = sem->count & RWSEM_ACTIVE_MASK; + if (prev==old) + sem->count = (sem->count & ~RWSEM_ACTIVE_MASK) | new; + spin_unlock(&sem->lock); + + return prev; +} + +#endif /* __KERNEL__ */ +#endif /* _LINUX_RWSEM_SPINLOCK_H */ diff -u --recursive --new-file v2.4.3/linux/include/linux/rwsem.h linux/include/linux/rwsem.h --- v2.4.3/linux/include/linux/rwsem.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/rwsem.h Tue Apr 17 17:19:36 2001 @@ -0,0 +1,156 @@ +/* rwsem.h: R/W semaphores, public interface + * + * Written by David Howells (dhowells@redhat.com). + * Derived from asm-i386/semaphore.h + * + * + * The MSW of the count is the negated number of active writers and waiting + * lockers, and the LSW is the total number of active locks + * + * The lock count is initialized to 0 (no active and no waiting lockers). + * + * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an + * uncontended lock. This can be determined because XADD returns the old value. + * Readers increment by 1 and see a positive value when uncontended, negative + * if there are writers (and maybe) readers waiting (in which case it goes to + * sleep). + * + * The value of WAITING_BIAS supports up to 32766 waiting processes. This can + * be extended to 65534 by manually checking the whole MSW rather than relying + * on the S flag. + * + * The value of ACTIVE_BIAS supports up to 65535 active processes. + * + * This should be totally fair - if anything is waiting, a process that wants a + * lock will go to the back of the queue. When the currently active lock is + * released, if there's a writer at the front of the queue, then that and only + * that will be woken up; if there's a bunch of consequtive readers at the + * front, then they'll all be woken up, but no other readers will be. + */ + +#ifndef _LINUX_RWSEM_H +#define _LINUX_RWSEM_H + +#include <linux/linkage.h> + +#define RWSEM_DEBUG 0 +#define RWSEM_DEBUG_MAGIC 0 + +#ifdef __KERNEL__ + +#include <asm/system.h> +#include <asm/atomic.h> +#include <linux/wait.h> + +#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK +#include <linux/rwsem-spinlock.h> /* use a generic implementation */ +#else +#include <asm/rwsem.h> /* use an arch-specific implementation */ +#endif + +/* defined contention handler functions for the generic case + * - these are also used for the exchange-and-add based algorithm + */ +#if defined(CONFIG_RWSEM_GENERIC) || defined(CONFIG_RWSEM_XCHGADD_ALGORITHM) +/* we use FASTCALL convention for the helpers */ +extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem)); +#endif + +#ifndef rwsemtrace +#if RWSEM_DEBUG +#include <asm/current.h> +#define rwsemtrace(SEM,FMT) do { if ((SEM)->debug) printk("[%d] "FMT"(count=%08lx)\n",current->pid,(SEM)->count); } while(0) +#else +#define rwsemtrace(SEM,FMT) +#endif +#endif + +/* + * lock for reading + */ +static inline void down_read(struct rw_semaphore *sem) +{ + rwsemtrace(sem,"Entering down_read"); + +#if RWSEM_DEBUG_MAGIC + if (sem->__magic != (long)&sem->__magic) + BUG(); +#endif + + __down_read(sem); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif + + rwsemtrace(sem,"Leaving down_read"); +} + +/* + * lock for writing + */ +static inline void down_write(struct rw_semaphore *sem) +{ + rwsemtrace(sem,"Entering down_write"); + +#if RWSEM_DEBUG_MAGIC + if (sem->__magic != (long)&sem->__magic) + BUG(); +#endif + + __down_write(sem); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + atomic_inc(&sem->writers); +#endif + + rwsemtrace(sem,"Leaving down_write"); +} + +/* + * release a read lock + */ +static inline void up_read(struct rw_semaphore *sem) +{ + rwsemtrace(sem,"Entering up_read"); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); + + rwsemtrace(sem,"Leaving up_read"); +} + +/* + * release a write lock + */ +static inline void up_write(struct rw_semaphore *sem) +{ + rwsemtrace(sem,"Entering up_write"); + +#if RWSEM_DEBUG_MAGIC + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); + + rwsemtrace(sem,"Leaving up_write"); +} + + +#endif /* __KERNEL__ */ +#endif /* _LINUX_RWSEM_H */ diff -u --recursive --new-file v2.4.3/linux/include/linux/scc.h linux/include/linux/scc.h --- v2.4.3/linux/include/linux/scc.h Thu Jan 4 12:50:12 2001 +++ linux/include/linux/scc.h Thu Apr 12 12:20:31 2001 @@ -213,8 +213,6 @@ /* SCC channel structure */ struct scc_channel { - int magic; /* magic word */ - int init; /* channel exists? */ struct net_device *dev; /* link to device control structure */ diff -u --recursive --new-file v2.4.3/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.4.3/linux/include/linux/sched.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/sched.h Tue Apr 17 14:43:51 2001 @@ -548,6 +548,8 @@ extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr)); extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)); +extern int FASTCALL(__wake_up_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit)); +extern int FASTCALL(__wake_up_sync_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit)); extern void FASTCALL(sleep_on(wait_queue_head_t *q)); extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); @@ -566,6 +568,8 @@ #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE, 0) #define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) #define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, nr) +#define wake_up_ctx(x,count,bit) __wake_up_ctx((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,count,bit) +#define wake_up_sync_ctx(x,count,bit) __wake_up_ctx((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,count,bit) asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); extern int in_group_p(gid_t); diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_asy.h linux/include/linux/sdla_asy.h --- v2.4.3/linux/include/linux/sdla_asy.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/sdla_asy.h Thu Apr 12 12:11:39 2001 @@ -0,0 +1,226 @@ +/***************************************************************************** +* sdla_asy.h Header file for the Sangoma S508/S514 asynchronous code API +* +* Author: Gideon Hack +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* +* Jan 28, 2000 Gideon Hack Initial Version +* +*****************************************************************************/ + + +#ifndef _WANPIPE_ASYNC_H +#define _WANPIPE_ASYNC_H + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +#define SET_ASY_CONFIGURATION 0xE2 /* set the asychronous operational configuration */ +#define READ_ASY_CONFIGURATION 0xE3 /* read the current asychronous operational configuration */ +#define ENABLE_ASY_COMMUNICATIONS 0xE4 /* enable asychronous communications */ +#define DISABLE_ASY_COMMUNICATIONS 0xE5 /* disable asychronous communications */ +#define READ_ASY_OPERATIONAL_STATS 0xE7 /* retrieve the asychronous operational statistics */ +#define FLUSH_ASY_OPERATIONAL_STATS 0xE8 /* flush the asychronous operational statistics */ +#define TRANSMIT_ASY_BREAK_SIGNAL 0xEC /* transmit an asychronous break signal */ + + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define COMMAND_INVALID_FOR_PORT 0x50 /* the command is invalid for the selected port */ +#define DISABLE_ASY_COMMS_BEFORE_CFG 0xE1 /* communications must be disabled before setting the configuration */ +#define ASY_COMMS_ENABLED 0xE1 /* communications are currently enabled */ +#define ASY_COMMS_DISABLED 0xE1 /* communications are currently disabled */ +#define ASY_CFG_BEFORE_COMMS_ENABLED 0xE2 /* perform a SET_ASY_CONFIGURATION before enabling comms */ +#define LGTH_ASY_CFG_DATA_INVALID 0xE2 /* the length of the passed configuration data is invalid */ +#define INVALID_ASY_CFG_DATA 0xE3 /* the passed configuration data is invalid */ +#define ASY_BREAK_SIGNAL_BUSY 0xEC /* a break signal is being transmitted */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_ASY_CONFIGURATION/READ_ASY_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the asynchronous configuration structure */ +typedef struct { + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ + unsigned short asy_API_options PACKED; /* asynchronous API options */ + unsigned short asy_protocol_options PACKED; /* asynchronous protocol options */ + unsigned short Tx_bits_per_char PACKED; /* number of bits per tx character */ + unsigned short Rx_bits_per_char PACKED; /* number of bits per received character */ + unsigned short stop_bits PACKED; /* number of stop bits per character */ + unsigned short parity PACKED; /* parity definition */ + unsigned short break_timer PACKED; /* the break signal timer */ + unsigned short asy_Rx_inter_char_timer PACKED; /* the receive inter-character timer */ + unsigned short asy_Rx_complete_length PACKED; /* the receive 'buffer complete' length */ + unsigned short XON_char PACKED; /* the XON character */ + unsigned short XOFF_char PACKED; /* the XOFF character */ + unsigned short asy_statistics_options PACKED; /* async operational stat options */ + unsigned long ptr_shared_mem_info_struct PACKED;/* ptr to the shared memory area information structure */ + unsigned long ptr_asy_Tx_stat_el_cfg_struct PACKED;/* ptr to the transmit status element configuration structure */ + unsigned long ptr_asy_Rx_stat_el_cfg_struct PACKED;/* ptr to the receive status element configuration structure */ +} ASY_CONFIGURATION_STRUCT; + +/* permitted minimum and maximum values for setting the asynchronous configuration */ +#define MIN_ASY_BAUD_RATE 50 /* maximum baud rate */ +#define MAX_ASY_BAUD_RATE 250000 /* minimum baud rate */ +#define MIN_ASY_BITS_PER_CHAR 5 /* minimum number of bits per character */ +#define MAX_ASY_BITS_PER_CHAR 8 /* maximum number of bits per character */ +#define MIN_BREAK_TMR_VAL 0 /* minimum break signal timer */ +#define MAX_BREAK_TMR_VAL 5000 /* maximum break signal timer */ +#define MIN_ASY_RX_INTER_CHAR_TMR 0 /* minimum receive inter-character timer */ +#define MAX_ASY_RX_INTER_CHAR_TMR 30000 /* maximum receive inter-character timer */ +#define MIN_ASY_RX_CPLT_LENGTH 0 /* minimum receive 'length complete' value */ +#define MAX_ASY_RX_CPLT_LENGTH 2000 /* maximum receive 'length complete' value */ + +/* bit settings for the 'asy_API_options' */ +#define ASY_RX_DATA_TRANSPARENT 0x0001 /* do not strip parity and unused bits from received characters */ + +/* bit settings for the 'asy_protocol_options' */ +#define ASY_RTS_HS_FOR_RX 0x0001 /* RTS handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_RX 0x0002 /* XON/XOFF handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_TX 0x0004 /* XON/XOFF handshaking is used for transmission control */ +#define ASY_DCD_HS_FOR_TX 0x0008 /* DCD handshaking is used for transmission control */ +#define ASY_CTS_HS_FOR_TX 0x0020 /* CTS handshaking is used for transmission control */ + +/* bit settings for the 'stop_bits' definition */ +#define ONE_STOP_BIT 1 /* representation for 1 stop bit */ +#define TWO_STOP_BITS 2 /* representation for 2 stop bits */ +#define ONE_AND_A_HALF_STOP_BITS 3 /* representation for 1.5 stop bits */ + +/* bit settings for the 'parity' definition */ +#define NO_PARITY 0 /* representation for no parity */ +#define ODD_PARITY 1 /* representation for odd parity */ +#define EVEN_PARITY 2 /* representation for even parity */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command (asynchronous mode) + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count PACKED; /* receiver overrun error count */ + unsigned short Rx_parity_err_count PACKED; /* parity errors received count */ + unsigned short Rx_framing_err_count PACKED; /* framing errors received count */ + unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_2 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_3 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_4 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_5 PACKED;/* reserved for later use */ + unsigned short DCD_state_change_count PACKED; /* DCD state change count */ + unsigned short CTS_state_change_count PACKED; /* CTS state change count */ +} ASY_COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_ASY_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the asynchronous operational statistics structure */ +typedef struct { + + /* Data transmission statistics */ + unsigned long Data_blocks_Tx_count PACKED;/* number of blocks transmitted */ + unsigned long Data_bytes_Tx_count PACKED;/* number of bytes transmitted */ + unsigned long Data_Tx_throughput PACKED;/* transmit throughput */ + unsigned long no_ms_for_Data_Tx_thruput_comp PACKED;/* millisecond time used for the Tx throughput computation */ + unsigned long Tx_Data_discard_lgth_err_count PACKED;/* number of Data blocks discarded (length error) */ + unsigned long reserved_Data_frm_Tx_stat1 PACKED;/* reserved for later use */ + unsigned long reserved_Data_frm_Tx_stat2 PACKED;/* reserved for later use */ + unsigned long reserved_Data_frm_Tx_stat3 PACKED;/* reserved for later use */ + + /* Data reception statistics */ + unsigned long Data_blocks_Rx_count PACKED;/* number of blocks received */ + unsigned long Data_bytes_Rx_count PACKED;/* number of bytes received */ + unsigned long Data_Rx_throughput PACKED;/* receive throughput */ + unsigned long no_ms_for_Data_Rx_thruput_comp PACKED;/* millisecond time used for the Rx throughput computation */ + unsigned long Rx_Data_bytes_discard_count PACKED;/* received Data bytes discarded */ + unsigned long reserved_Data_frm_Rx_stat1 PACKED;/* reserved for later use */ + + /* handshaking protocol statistics */ + unsigned short XON_chars_Tx_count PACKED; /* number of XON characters transmitted */ + unsigned short XOFF_chars_Tx_count PACKED; /* number of XOFF characters transmitted */ + unsigned short XON_chars_Rx_count PACKED; /* number of XON characters received */ + unsigned short XOFF_chars_Rx_count PACKED; /* number of XOFF characters received */ + unsigned short Tx_halt_modem_low_count PACKED; /* number of times Tx halted (modem line low) */ + unsigned short Rx_halt_RTS_low_count PACKED; /* number of times Rx halted by setting RTS low */ + unsigned long reserved_handshaking_stat1 PACKED;/* reserved for later use */ + + /* break statistics */ + unsigned short break_Tx_count PACKED; /* number of break sequences transmitted */ + unsigned short break_Rx_count PACKED; /* number of break sequences received */ + unsigned long reserved_break_stat1 PACKED;/* reserved for later use */ + + /* miscellaneous statistics */ + unsigned long reserved_misc_stat1 PACKED; /* reserved for later use */ + unsigned long reserved_misc_stat2 PACKED; /* reserved for later use */ + +} ASY_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data transmission + * --------------------------------------------------------------------------*/ + +/* the Data block transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ +} ASY_TX_STATUS_EL_CFG_STRUCT; + + +/* the Data block transmit status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short data_length PACKED; /* length of the block to be transmitted */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long reserved_3 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} ASY_DATA_TX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data reception + * --------------------------------------------------------------------------*/ + +/* the Data block receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements PACKED;/* number of receive status elements */ + unsigned long base_addr_Rx_status_elements PACKED;/* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use PACKED;/* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer PACKED;/* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer PACKED;/* end address of the receive data buffer */ +} ASY_RX_STATUS_EL_CFG_STRUCT; + +/* the Data block receive status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short data_length PACKED; /* length of the received data block */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ + unsigned short data_buffered PACKED; /* the number of data bytes still buffered */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} ASY_DATA_RX_STATUS_EL_STRUCT; + +#endif diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_chdlc.h linux/include/linux/sdla_chdlc.h --- v2.4.3/linux/include/linux/sdla_chdlc.h Wed Jan 26 13:25:58 2000 +++ linux/include/linux/sdla_chdlc.h Thu Apr 12 12:11:39 2001 @@ -4,7 +4,7 @@ Author: Gideon Hack Nenad Corbic <ncorbic@sangoma.com> - Copyright: (c) 1995-1999 Sangoma Technologies Inc. + Copyright: (c) 1995-2000 Sangoma Technologies Inc. This program is free software; you can redistribute it and/or modify it under the term of the GNU General Public License @@ -137,6 +137,8 @@ #define TRACE_PROT 0x01 #define TRACE_DATA 0x02 +#define DISCARD_RX_ERROR_FRAMES 0x0001 + /* ---------------------------------------------------------------------------- * Return codes from interface commands * --------------------------------------------------------------------------*/ @@ -358,6 +360,9 @@ #define IGNORE_KPALV_FOR_LINK_STAT 0x0004 /* ignore keepalive frames in determining the CHDLC link status */ +#define SINGLE_TX_BUFFER 0x4000 +/* configure a single transmit buffer */ + #define HDLC_STREAMING_MODE 0x8000 /* settings for the 'CHDLC_statistics_options' */ @@ -469,7 +474,7 @@ unsigned long reserved_CDP_stat5 PACKED; /* reserved for later */ unsigned long reserved_CDP_stat6 PACKED; /* reserved for later */ - /* Incomming frames with a format error statistics */ + /* Incoming frames with a format error statistics */ unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED; /* frames received of with incomplete Cisco HDLC header */ unsigned short Rx_frms_too_long_count PACKED; /* frames received of excessive length count */ unsigned short Rx_invalid_CHDLC_addr_count PACKED; /* frames received with an invalid CHDLC address count */ @@ -484,7 +489,7 @@ unsigned long reserved_frm_format_err4 PACKED; /* reserved for later */ /* CHDLC timeout/retry statistics */ - unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incomming SLARP frames */ + unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incoming SLARP frames */ unsigned short SLARP_Request_TO_count PACKED; /* timeout count for SLARP Request frames */ unsigned long To_retry_reserved_stat1 PACKED; /* reserved for later */ unsigned long To_retry_reserved_stat2 PACKED; /* reserved for later */ diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_fr.h linux/include/linux/sdla_fr.h --- v2.4.3/linux/include/linux/sdla_fr.h Wed Jan 26 13:25:58 2000 +++ linux/include/linux/sdla_fr.h Thu Apr 12 12:11:39 2001 @@ -4,7 +4,7 @@ * Author: Gideon Hack * Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -541,7 +541,7 @@ } fr_encap_hdr_t; typedef struct { - fr_encap_hdr_t fr_encap_hdr PACKED; +// fr_encap_hdr_t fr_encap_hdr PACKED; ip_pkt_t ip_pkt PACKED; udp_pkt_t udp_pkt PACKED; wp_mgmt_t wp_mgmt PACKED; diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_ppp.h linux/include/linux/sdla_ppp.h --- v2.4.3/linux/include/linux/sdla_ppp.h Wed Jan 26 13:25:58 2000 +++ linux/include/linux/sdla_ppp.h Thu Apr 12 12:11:39 2001 @@ -1,7 +1,7 @@ /***************************************************************************** * sdla_ppp.h Sangoma PPP firmware API definitions. * -* Author: Gene Kozin <74604.152@compuserve.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -10,6 +10,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Feb 24, 2000 Nenad Corbic v2.1.2 * Jan 06, 1997 Gene Kozin v2.0 * Apr 11, 1996 Gene Kozin Initial version. *****************************************************************************/ @@ -214,7 +215,8 @@ { unsigned short txb_num PACKED; /* 00: number of transmit buffers */ unsigned long txb_ptr PACKED; /* 02: pointer to the buffer ctl. */ - unsigned char rsrv1[26] PACKED; + unsigned long txb_nxt PACKED; + unsigned char rsrv1[22] PACKED; unsigned short rxb_num PACKED; /* 20: number of receive buffers */ unsigned long rxb_ptr PACKED; /* 22: pointer to the buffer ctl. */ unsigned long rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */ diff -u --recursive --new-file v2.4.3/linux/include/linux/sdla_x25.h linux/include/linux/sdla_x25.h --- v2.4.3/linux/include/linux/sdla_x25.h Wed Jun 24 14:34:44 1998 +++ linux/include/linux/sdla_x25.h Thu Apr 12 12:11:39 2001 @@ -1,15 +1,16 @@ /***************************************************************************** * sdla_x25.h Sangoma X.25 firmware API definitions. * -* Author: Gene Kozin <74604.152@compuserve.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * 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. + 2 of the License, or (at your option) any later version. * ============================================================================ +* Feb 28, 2000 Nenad Corbic Updated for socket based x25api * Dec 13, 1996 Gene Kozin Initial version *****************************************************************************/ #ifndef _SDLA_X25_H @@ -18,39 +19,35 @@ /*---------------------------------------------------------------------------- * Notes: * ------ - * 1. All structures defined in this file are byte-aligned. To ensure - * portability of this code between different platforms and compilers, one - * of the following defines must be defined before including this file: - * - * Compiler Platform Define Use option - * -------- -------- ------ ---------- - * GNU C Linux _GNUC_ - - * Microsoft C DOS/Windows _MSC_ - + * 1. All structures defined in this file are byte-alined. + * Compiler Platform + * -------- -------- + * GNU C Linux * */ -#ifdef _GNUC_ -# ifndef PACKED -# define PACKED __attribute__((packed)) -# endif /* PACKED */ -#else -# define PACKED -#endif -#ifdef _MSC_ -# pragma pack(1) -#endif +#ifndef PACKED +# define PACKED __attribute__((packed)) +#endif /* PACKED */ /****** CONSTANTS DEFINITIONS ***********************************************/ #define X25_MAX_CHAN 255 /* max number of open X.25 circuits */ #define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ - /* * X.25 shared memory layout. */ #define X25_MBOX_OFFS 0x16B0 /* general mailbox block */ #define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */ #define X25_STATUS_OFFS 0x1EF0 /* X.25 status structure */ +#define X25_MB_VECTOR 0xE000 /* S514 mailbox window vecotr */ +#define X25_MISC_HDLC_BITS 0x1F00 /*X.25 miscallaneous HDLC bits */ + +/* code levels */ +#define HDLC_LEVEL 0x01 +#define X25_LEVEL 0x02 +#define X25_AND_HDLC_LEVEL 0x03 +#define DO_HDLC_LEVEL_ERROR_CHECKING 0x04 /****** DATA STRUCTURES *****************************************************/ @@ -100,11 +97,12 @@ #define X25_HDLC_READ 0x21 /* read HDLC information frame */ #define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */ #define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */ +#define SET_PROTOCOL_LEVEL 0x1F /* set protocol level */ /*----- X.25-level commands -----------*/ #define X25_READ 0x22 /* read X.25 packet */ #define X25_WRITE 0x23 /* send X.25 packet */ #define X25_PLACE_CALL 0x30 /* place a call on SVC */ -#define X25_ACCEPT_CALL 0x31 /* accept incoming call */ +#define X25_ACCEPT_CALL 0x31 /* accept incomming call */ #define X25_CLEAR_CALL 0x32 /* clear call */ #define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ #define X25_RESET 0x34 /* send reset request packet */ @@ -116,14 +114,14 @@ #define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ #define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ #define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ -#define X25_INCOMING_CALL_CTL 0x41 /* select incoming call options */ +#define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ #define X25_CONFIGURE_PVC 0x42 /* configure PVC */ #define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ #define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ #define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ #define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ #define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ -#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowledged */ +#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ #define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ #define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ #define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ @@ -139,7 +137,7 @@ #define X25RES_LINK_CLOSED 0x03 #define X25RES_INVAL_LENGTH 0x04 #define X25RES_INVAL_CMD 0x05 -#define X25RES_UNNUMBERED_FRAME 0x06 /* unnumbered frame received */ +#define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ #define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ #define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ #define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ @@ -153,13 +151,13 @@ #define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ #define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ #define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ -#define X25RES_INVAL_CALL_ARG 0x3A /* erroneous call arguments */ -#define X25RES_INVAL_CALL_DATA 0x3B /* erroneous call user data */ +#define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ +#define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ #define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ -#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occurred */ +#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ #define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ #define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ -/*----- Command-dependent results -----*/ +/*----- Command-dependant results -----*/ #define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ #define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ #define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ @@ -167,7 +165,7 @@ #define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ #define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ #define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ -#define X25RES_INVAL_PARAM 0x31 /* INCOMING_CALL_CTL */ +#define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ #define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ /* @@ -207,6 +205,22 @@ #define PVE_RESTART_RQST 0x34 #define PVE_DIAGNOSTIC 0x37 +#define INTR_ON_RX_FRAME 0x01 +#define INTR_ON_TX_FRAME 0x02 +#define INTR_ON_MODEM_STATUS_CHANGE 0x04 +#define INTR_ON_COMMAND_COMPLETE 0x08 +#define INTR_ON_X25_ASY_TRANSACTION 0x10 +#define INTR_ON_TIMER 0x40 +#define DIRECT_RX_INTR_USAGE 0x80 + +#define NO_INTR_PENDING 0x00 +#define RX_INTR_PENDING 0x01 +#define TX_INTR_PENDING 0x02 +#define MODEM_INTR_PENDING 0x04 +#define COMMAND_COMPLETE_INTR_PENDING 0x08 +#define X25_ASY_TRANS_INTR_PENDING 0x10 +#define TIMER_INTR_PENDING 0x40 + /*---------------------------------------------------------------------------- * X.25 Mailbox. * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS @@ -239,7 +253,7 @@ typedef struct X25Status { unsigned short pvc_map PACKED; /* 00h: PVC map */ - unsigned short icc_map PACKED; /* 02h: Incoming Chan. map */ + unsigned short icc_map PACKED; /* 02h: Incomming Chan. map */ unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */ unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */ TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ @@ -256,7 +270,7 @@ #define X25_RX_INTR 0x01 /* receive interrupt */ #define X25_TX_INTR 0x02 /* transmit interrupt */ #define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ -#define X25_EVENT_INTR 0x10 /* asynchronous event encountered */ +#define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ #define X25_CMD_INTR 0x08 /* interface command complete */ /* @@ -374,7 +388,7 @@ */ typedef struct X25Config { - unsigned char baudRate PACKED; /* 00h: */ +unsigned char baudRate PACKED; /* 00h: */ unsigned char t1 PACKED; /* 01h: */ unsigned char t2 PACKED; /* 02h: */ unsigned char n2 PACKED; /* 03h: */ @@ -390,8 +404,8 @@ unsigned short pktMTU PACKED; /* 0Fh: */ unsigned short loPVC PACKED; /* 11h: */ unsigned short hiPVC PACKED; /* 13h: */ - unsigned short loIncomingSVC PACKED; /* 15h: */ - unsigned short hiIncomingSVC PACKED; /* 17h: */ + unsigned short loIncommingSVC PACKED; /* 15h: */ + unsigned short hiIncommingSVC PACKED; /* 17h: */ unsigned short loTwoWaySVC PACKED; /* 19h: */ unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ unsigned short loOutgoingSVC PACKED; /* 1Dh: */ @@ -421,8 +435,8 @@ { unsigned short loPVC PACKED; /* 00h: lowest PVC number */ unsigned short hiPVC PACKED; /* 02h: highest PVC number */ - unsigned short loIncomingSVC PACKED; /* 04h: lowest incoming SVC */ - unsigned short hiIncomingSVC PACKED; /* 06h: highest incoming SVC */ + unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ + unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ @@ -499,7 +513,7 @@ /* * Defines for the 'type' field. */ -#define X25LOG_INCOMING 0x00 +#define X25LOG_INCOMMING 0x00 #define X25LOG_APPLICATION 0x01 #define X25LOG_AUTOMATIC 0x02 #define X25LOG_ERROR 0x04 @@ -568,7 +582,7 @@ #define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ #define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ #define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ -#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmission error */ +#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ #define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ /***************************************************************************** @@ -582,7 +596,7 @@ unsigned char data[0] PACKED; } THDLCFrame; -typedef struct X25Pkt /*----- X.25 Packet Format ----------*/ +typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ { unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ @@ -619,7 +633,140 @@ #define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */ #define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */ -#ifdef _MSC_ -# pragma pack() -#endif + +typedef struct { + TX25Cmd cmd PACKED; + char data[X25_MAX_DATA] PACKED; +} mbox_cmd_t; + + +typedef struct { + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; + unsigned short length PACKED; + unsigned char result PACKED; + unsigned short lcn PACKED; + char reserved[7] PACKED; +}x25api_hdr_t; + + +typedef struct { + x25api_hdr_t hdr PACKED; + char data[X25_MAX_DATA] PACKED; +}x25api_t; + + +/* + * XPIPEMON Definitions + */ + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 +#define UDPMGMT_XPIPE_SIGNATURE "XLINK8ND" +#define UDPMGMT_DRVRSTATS_SIGNATURE "DRVSTATS" + +/* values for request/reply byte */ +#define UDPMGMT_REQUEST 0x01 +#define UDPMGMT_REPLY 0x02 +#define UDP_OFFSET 12 + + +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} cblock_t; + +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + unsigned char data[4080] PACKED; +} x25_udp_pkt_t; + + +typedef struct read_hdlc_stat { + unsigned short inf_frames_rx_ok PACKED; + unsigned short inf_frames_rx_out_of_seq PACKED; + unsigned short inf_frames_rx_no_data PACKED; + unsigned short inf_frames_rx_dropped PACKED; + unsigned short inf_frames_rx_data_too_long PACKED; + unsigned short inf_frames_rx_invalid_addr PACKED; + unsigned short inf_frames_tx_ok PACKED; + unsigned short inf_frames_tx_retransmit PACKED; + unsigned short T1_timeouts PACKED; + unsigned short SABM_frames_rx PACKED; + unsigned short DISC_frames_rx PACKED; + unsigned short DM_frames_rx PACKED; + unsigned short FRMR_frames_rx PACKED; + unsigned short SABM_frames_tx PACKED; + unsigned short DISC_frames_tx PACKED; + unsigned short DM_frames_tx PACKED; + unsigned short FRMR_frames_tx PACKED; +} read_hdlc_stat_t; + +typedef struct read_comms_err_stats{ + unsigned char overrun_err_rx PACKED; + unsigned char CRC_err PACKED; + unsigned char abort_frames_rx PACKED; + unsigned char frames_dropped_buf_full PACKED; + unsigned char abort_frames_tx PACKED; + unsigned char transmit_underruns PACKED; + unsigned char missed_tx_underruns_intr PACKED; + unsigned char reserved PACKED; + unsigned char DCD_drop PACKED; + unsigned char CTS_drop PACKED; +} read_comms_err_stats_t; + +typedef struct trace_data { + unsigned short length PACKED; + unsigned char type PACKED; + unsigned char trace_dropped PACKED; + unsigned char reserved[5] PACKED; + unsigned short timestamp PACKED; + unsigned char data PACKED; +} trace_data_t; + +enum {UDP_XPIPE_TYPE}; + +#define XPIPE_ENABLE_TRACING 0x14 +#define XPIPE_DISABLE_TRACING 0x14 +#define XPIPE_GET_TRACE_INFO 0x16 +#define XPIPE_FT1_READ_STATUS 0x74 +#define XPIPE_DRIVER_STAT_IFSEND 0x75 +#define XPIPE_DRIVER_STAT_INTR 0x76 +#define XPIPE_DRIVER_STAT_GEN 0x77 +#define XPIPE_FLUSH_DRIVER_STATS 0x78 +#define XPIPE_ROUTER_UP_TIME 0x79 +#define XPIPE_SET_FT1_MODE 0x81 +#define XPIPE_FT1_STATUS_CTRL 0x80 + + +/* error messages */ +#define NO_BUFFS_OR_CLOSED_WIN 0x33 +#define DATA_LENGTH_TOO_BIG 0x32 +#define NO_DATA_AVAILABLE 0x33 +#define Z80_TIMEOUT_ERROR 0x0a +#define NO_BUFFS 0x08 + + +/* Trace options */ +#define TRACE_DEFAULT 0x03 +#define TRACE_SUPERVISOR_FRMS 0x10 +#define TRACE_ASYNC_FRMS 0x20 +#define TRACE_ALL_HDLC_FRMS 0x40 +#define TRACE_DATA_FRMS 0x08 + + #endif /* _SDLA_X25_H */ diff -u --recursive --new-file v2.4.3/linux/include/linux/sdladrv.h linux/include/linux/sdladrv.h --- v2.4.3/linux/include/linux/sdladrv.h Mon Dec 11 13:00:00 2000 +++ linux/include/linux/sdladrv.h Thu Apr 12 12:11:39 2001 @@ -3,7 +3,7 @@ * * Author: Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,13 +20,21 @@ #define _SDLADRV_H #include <linux/version.h> -#if LINUX_VERSION_CODE >= 0x020100 + +#ifndef KERNEL_VERSION + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +#define LINUX_2_4 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) #define LINUX_2_1 +#else +#define LINUX_2_0 #endif #define SDLA_MAXIORANGE 4 /* maximum I/O port range */ #define SDLA_WINDOWSIZE 0x2000 /* default dual-port memory window size */ - /****** Data Structures *****************************************************/ /*---------------------------------------------------------------------------- @@ -41,7 +49,8 @@ int irq; /* interrupt request level */ char S514_cpu_no[1]; /* PCI CPU Number */ unsigned char S514_slot_no; /* PCI Slot Number */ -#ifdef LINUX_2_1 + char auto_pci_cfg; /* Autodetect PCI Slot */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct pci_dev *pci_dev; /* PCI device */ #else unsigned char pci_bus; /* PCI bus number */ @@ -73,5 +82,7 @@ extern int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len); extern int sdla_exec (void* opflag); + +extern unsigned wanpipe_hw_probe(void); #endif /* _SDLADRV_H */ diff -u --recursive --new-file v2.4.3/linux/include/linux/sdlapci.h linux/include/linux/sdlapci.h --- v2.4.3/linux/include/linux/sdlapci.h Wed Jan 26 13:25:58 2000 +++ linux/include/linux/sdlapci.h Thu Apr 12 12:11:39 2001 @@ -4,7 +4,7 @@ * * Author: Gideon Hack <ghack@sangoma.com> * -* Copyright: (c) 1999 Sangoma Technologies Inc. +* Copyright: (c) 1999-2000 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -62,7 +62,11 @@ #define S514_CPU_START 0x01 /* The maximum number of S514 adapters supported */ -#define MAX_S514_CARDS 8 +#define MAX_S514_CARDS 20 + +#define PCI_CARD_TYPE 0x2E +#define S514_DUAL_CPU 0x12 +#define S514_SINGLE_CPU 0x11 #endif /* _SDLAPCI_H */ diff -u --recursive --new-file v2.4.3/linux/include/linux/serialP.h linux/include/linux/serialP.h --- v2.4.3/linux/include/linux/serialP.h Mon Mar 26 15:50:00 2001 +++ linux/include/linux/serialP.h Tue Apr 17 14:45:28 2001 @@ -181,7 +181,7 @@ #define SPCI_FL_IRQBASE4 (0x0004 << 4) #define SPCI_FL_GET_IRQBASE(x) ((x & SPCI_FL_IRQ_MASK) >> 4) -/* Use sucessive BARs (PCI base address registers), +/* Use successive BARs (PCI base address registers), else use offset into some specified BAR */ #define SPCI_FL_BASE_TABLE 0x0100 diff -u --recursive --new-file v2.4.3/linux/include/linux/serio.h linux/include/linux/serio.h --- v2.4.3/linux/include/linux/serio.h Wed Jun 21 08:22:21 2000 +++ linux/include/linux/serio.h Thu Apr 12 12:20:31 2001 @@ -2,7 +2,7 @@ #define _SERIO_H /* - * $Id: serio.h,v 1.7 2000/06/01 11:39:46 vojtech Exp $ + * $Id: serio.h,v 1.8 2000/07/17 10:42:14 vojtech Exp $ * * Copyright (C) 1999 Vojtech Pavlik * @@ -103,6 +103,7 @@ #define SERIO_SPACEBALL 0x1b #define SERIO_GUNZE 0x1c #define SERIO_IFORCE 0x1d +#define SERIO_STINGER 0x1e #define SERIO_ID 0xff00UL #define SERIO_EXTRA 0xff0000UL diff -u --recursive --new-file v2.4.3/linux/include/linux/shmem_fs.h linux/include/linux/shmem_fs.h --- v2.4.3/linux/include/linux/shmem_fs.h Fri Dec 29 14:07:24 2000 +++ linux/include/linux/shmem_fs.h Thu Apr 12 12:25:53 2001 @@ -19,6 +19,7 @@ struct shmem_inode_info { spinlock_t lock; + unsigned long max_index; swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */ swp_entry_t **i_indirect; /* doubly indirect blocks */ unsigned long swapped; diff -u --recursive --new-file v2.4.3/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.4.3/linux/include/linux/skbuff.h Mon Mar 26 15:48:19 2001 +++ linux/include/linux/skbuff.h Tue Apr 17 14:44:04 2001 @@ -18,10 +18,13 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/time.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/types.h> #include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/highmem.h> #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ @@ -31,6 +34,47 @@ #define CHECKSUM_HW 1 #define CHECKSUM_UNNECESSARY 2 +#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES-1)) & ~(SMP_CACHE_BYTES-1)) +#define SKB_MAX_HEAD(X) ((PAGE_SIZE - (X) - sizeof(struct skb_shared_info))&~(SMP_CACHE_BYTES-1)) + +/* A. Checksumming of received packets by device. + * + * NONE: device failed to checksum this packet. + * skb->csum is undefined. + * + * UNNECESSARY: device parsed packet and wouldbe verified checksum. + * skb->csum is undefined. + * It is bad option, but, unfortunately, many of vendors do this. + * Apparently with secret goal to sell you new device, when you + * will add new protocol to your host. F.e. IPv6. 8) + * + * HW: the most generic way. Device supplied checksum of _all_ + * the packet as seen by netif_rx in skb->csum. + * NOTE: Even if device supports only some protocols, but + * is able to produce some skb->csum, it MUST use HW, + * not UNNECESSARY. + * + * B. Checksumming on output. + * + * NONE: skb is checksummed by protocol or csum is not required. + * + * HW: device is required to csum packet as seen by hard_start_xmit + * from skb->h.raw to the end and to record the checksum + * at skb->h.raw+skb->csum. + * + * Device must show its capabilities in dev->features, set + * at device setup time. + * NETIF_F_HW_CSUM - it is clever device, it is able to checksum + * everything. + * NETIF_F_NO_CSUM - loopback or reliable single hop media. + * NETIF_F_IP_CSUM - device is dumb. It is able to csum only + * TCP/UDP over IPv4. Sigh. Vendors like this + * way by an unknown reason. Though, see comment above + * about CHECKSUM_UNNECESSARY. 8) + * + * Any questions? No questions, good. --ANK + */ + #ifdef __i386__ #define NET_CALLER(arg) (*(((void**)&arg)-1)) #else @@ -57,6 +101,29 @@ spinlock_t lock; }; +struct sk_buff; + +#define MAX_SKB_FRAGS 6 + +typedef struct skb_frag_struct skb_frag_t; + +struct skb_frag_struct +{ + struct page *page; + __u16 page_offset; + __u16 size; +}; + +/* This data is invariant across clones and lives at + * the end of the header data, ie. at skb->end. + */ +struct skb_shared_info { + atomic_t dataref; + unsigned int nr_frags; + struct sk_buff *frag_list; + skb_frag_t frags[MAX_SKB_FRAGS]; +}; + struct sk_buff { /* These two members must be first. */ struct sk_buff * next; /* Next buffer in list */ @@ -107,9 +174,10 @@ char cb[48]; unsigned int len; /* Length of actual data */ + unsigned int data_len; unsigned int csum; /* Checksum */ - volatile char used; /* Data moved to user and not MSG_PEEK */ - unsigned char cloned, /* head may be cloned (check refcnt to be sure). */ + unsigned char __unused, /* Dead field, may be reused */ + cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ ip_summed; /* Driver fed us an IP checksum */ __u32 priority; /* Packet queueing priority */ @@ -122,6 +190,7 @@ unsigned char *data; /* Data head pointer */ unsigned char *tail; /* Tail pointer */ unsigned char *end; /* End pointer */ + void (*destructor)(struct sk_buff *); /* Destruct function */ #ifdef CONFIG_NETFILTER /* Can be used for communication between hooks. */ @@ -158,11 +227,13 @@ #include <asm/system.h> extern void __kfree_skb(struct sk_buff *skb); -extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list); extern struct sk_buff * alloc_skb(unsigned int size, int priority); extern void kfree_skbmem(struct sk_buff *skb); extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); extern struct sk_buff * skb_copy(const struct sk_buff *skb, int priority); +extern struct sk_buff * pskb_copy(struct sk_buff *skb, int gfp_mask); +extern int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask); +extern struct sk_buff * skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom); extern struct sk_buff * skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, @@ -171,14 +242,8 @@ extern void skb_over_panic(struct sk_buff *skb, int len, void *here); extern void skb_under_panic(struct sk_buff *skb, int len, void *here); -/* Backwards compatibility */ -#define skb_realloc_headroom(skb, nhr) skb_copy_expand(skb, nhr, skb_tailroom(skb), GFP_ATOMIC) - /* Internal */ -static inline atomic_t *skb_datarefp(struct sk_buff *skb) -{ - return (atomic_t *)(skb->end); -} +#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end)) /** * skb_queue_empty - check if a queue is empty @@ -243,7 +308,7 @@ static inline int skb_cloned(struct sk_buff *skb) { - return skb->cloned && atomic_read(skb_datarefp(skb)) != 1; + return skb->cloned && atomic_read(&skb_shinfo(skb)->dataref) != 1; } /** @@ -679,6 +744,20 @@ return result; } +static inline int skb_is_nonlinear(const struct sk_buff *skb) +{ + return skb->data_len; +} + +static inline int skb_headlen(const struct sk_buff *skb) +{ + return skb->len - skb->data_len; +} + +#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) BUG(); } while (0) +#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) BUG(); } while (0) +#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) BUG(); } while (0) + /* * Add data to an sk_buff */ @@ -686,6 +765,7 @@ static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp=skb->tail; + SKB_LINEAR_ASSERT(skb); skb->tail+=len; skb->len+=len; return tmp; @@ -704,6 +784,7 @@ static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp=skb->tail; + SKB_LINEAR_ASSERT(skb); skb->tail+=len; skb->len+=len; if(skb->tail>skb->end) { @@ -742,6 +823,8 @@ static inline char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len-=len; + if (skb->len < skb->data_len) + BUG(); return skb->data+=len; } @@ -763,6 +846,33 @@ return __skb_pull(skb,len); } +extern unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta); + +static inline char *__pskb_pull(struct sk_buff *skb, unsigned int len) +{ + if (len > skb_headlen(skb) && + __pskb_pull_tail(skb, len-skb_headlen(skb)) == NULL) + return NULL; + skb->len -= len; + return skb->data += len; +} + +static inline unsigned char * pskb_pull(struct sk_buff *skb, unsigned int len) +{ + if (len > skb->len) + return NULL; + return __pskb_pull(skb,len); +} + +static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len) +{ + if (len <= skb_headlen(skb)) + return 1; + if (len > skb->len) + return 0; + return (__pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL); +} + /** * skb_headroom - bytes at buffer head * @skb: buffer to check @@ -784,7 +894,7 @@ static inline int skb_tailroom(const struct sk_buff *skb) { - return skb->end-skb->tail; + return skb_is_nonlinear(skb) ? 0 : skb->end-skb->tail; } /** @@ -802,11 +912,16 @@ skb->tail+=len; } +extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc); static inline void __skb_trim(struct sk_buff *skb, unsigned int len) { - skb->len = len; - skb->tail = skb->data+len; + if (!skb->data_len) { + skb->len = len; + skb->tail = skb->data+len; + } else { + ___pskb_trim(skb, len, 0); + } } /** @@ -825,6 +940,25 @@ } } + +static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) +{ + if (!skb->data_len) { + skb->len = len; + skb->tail = skb->data+len; + return 0; + } else { + return ___pskb_trim(skb, len, 1); + } +} + +static inline int pskb_trim(struct sk_buff *skb, unsigned int len) +{ + if (len < skb->len) + return __pskb_trim(skb, len); + return 0; +} + /** * skb_orphan - orphan a buffer * @skb: buffer to orphan @@ -920,32 +1054,57 @@ } /** - * skb_cow - copy a buffer if need be - * @skb: buffer to copy + * skb_cow - copy header of skb when it is required + * @skb: buffer to cow * @headroom: needed headroom * - * If the buffer passed lacks sufficient headroom or is a clone then - * it is copied and the additional headroom made available. If there - * is no free memory %NULL is returned. The new buffer is returned if - * a copy was made (and the old one dropped a reference). The existing - * buffer is returned otherwise. + * If the skb passed lacks sufficient headroom or its data part + * is shared, data is reallocated. If reallocation fails, an error + * is returned and original skb is not changed. * - * This function primarily exists to avoid making two copies when making - * a writable copy of a buffer and then growing the headroom. + * The result is skb with writable area skb->head...skb->tail + * and at least @headroom of space at head. */ - -static inline struct sk_buff * +static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) { - headroom = (headroom+15)&~15; + int delta = headroom - skb_headroom(skb); - if ((unsigned)skb_headroom(skb) < headroom || skb_cloned(skb)) { - struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom); - kfree_skb(skb); - skb = skb2; - } - return skb; + if (delta < 0) + delta = 0; + + if (delta || skb_cloned(skb)) + return pskb_expand_head(skb, (delta+15)&~15, 0, GFP_ATOMIC); + return 0; +} + +/** + * skb_linearize - convert paged skb to linear one + * @skb: buffer to linarize + * @gfp_mask: allocation mode + * + * If there is no free memory -ENOMEM is returned, otherwise zero + * is returned and the old skb data released. */ +int skb_linearize(struct sk_buff *skb, int gfp); + +static inline void *kmap_skb_frag(const skb_frag_t *frag) +{ +#ifdef CONFIG_HIGHMEM + if (in_irq()) + BUG(); + + local_bh_disable(); +#endif + return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); +} + +static inline void kunmap_skb_frag(void *vaddr) +{ + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); +#ifdef CONFIG_HIGHMEM + local_bh_enable(); +#endif } #define skb_queue_walk(queue, skb) \ @@ -956,9 +1115,15 @@ extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait); -extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); -extern int skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size); +extern int skb_copy_datagram(const struct sk_buff *from, int offset, char *to,int size); +extern int skb_copy_datagram_iovec(const struct sk_buff *from, int offset, struct iovec *to,int size); +extern int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump); +extern int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov); extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb); + +extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum); +extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); +extern unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum); extern void skb_init(void); extern void skb_add_mtu(int mtu); diff -u --recursive --new-file v2.4.3/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.4.3/linux/include/linux/socket.h Mon Mar 26 15:48:10 2001 +++ linux/include/linux/socket.h Tue Apr 17 14:43:34 2001 @@ -155,6 +155,7 @@ #define AF_SNA 22 /* Linux SNA Project (nutters!) */ #define AF_IRDA 23 /* IRDA sockets */ #define AF_PPPOX 24 /* PPPoX sockets */ +#define AF_WANPIPE 25 /* Wanpipe API Sockets */ #define AF_MAX 32 /* For now.. */ /* Protocol families, same as address families. */ @@ -184,6 +185,7 @@ #define PF_SNA AF_SNA #define PF_IRDA AF_IRDA #define PF_PPPOX AF_PPPOX +#define PF_WANPIPE AF_WANPIPE #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ @@ -209,6 +211,7 @@ #define MSG_RST 0x1000 #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ #define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ +#define MSG_MORE 0x8000 /* Sender will send more */ #define MSG_EOF MSG_FIN diff -u --recursive --new-file v2.4.3/linux/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h --- v2.4.3/linux/include/linux/sunrpc/sched.h Mon Mar 26 15:48:29 2001 +++ linux/include/linux/sunrpc/sched.h Tue Apr 17 14:43:42 2001 @@ -80,7 +80,7 @@ unsigned short tk_lock; /* Task lock counter */ unsigned char tk_active : 1,/* Task has been activated */ tk_wakeup : 1;/* Task waiting to wake up */ - unsigned int tk_runstate; /* Task run status */ + unsigned long tk_runstate; /* Task run status */ #ifdef RPC_DEBUG unsigned short tk_pid; /* debugging aid */ #endif diff -u --recursive --new-file v2.4.3/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.4.3/linux/include/linux/swap.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/swap.h Tue Apr 17 14:43:37 2001 @@ -134,7 +134,6 @@ extern void __delete_from_swap_cache(struct page *page); extern void delete_from_swap_cache(struct page *page); extern void delete_from_swap_cache_nolock(struct page *page); -extern void free_page_and_swap_cache(struct page *page); /* linux/mm/swapfile.c */ extern unsigned int nr_swapfiles; @@ -166,23 +165,6 @@ extern unsigned long swap_cache_find_total; extern unsigned long swap_cache_find_success; #endif - -/* - * Work out if there are any other processes sharing this page, ignoring - * any page reference coming from the swap cache, or from outstanding - * swap IO on this page. (The page cache _does_ count as another valid - * reference to the page, however.) - */ -static inline int is_page_shared(struct page *page) -{ - unsigned int count; - if (PageReserved(page)) - return 1; - count = page_count(page); - if (PageSwapCache(page)) - count += swap_count(page) - 2 - !!page->buffers; - return count > 1; -} extern spinlock_t pagemap_lru_lock; diff -u --recursive --new-file v2.4.3/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.4.3/linux/include/linux/sysctl.h Mon Mar 26 15:48:10 2001 +++ linux/include/linux/sysctl.h Tue Apr 17 14:43:33 2001 @@ -117,6 +117,8 @@ KERN_OVERFLOWGID=47, /* int: overflow GID */ KERN_SHMPATH=48, /* string: path to shm fs */ KERN_HOTPLUG=49, /* string: path to hotplug policy agent */ + KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */ + KERN_S390_USER_DEBUG_LOGGING=51 /* int: dumps of user faults */ }; diff -u --recursive --new-file v2.4.3/linux/include/linux/tcp.h linux/include/linux/tcp.h --- v2.4.3/linux/include/linux/tcp.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/tcp.h Tue Apr 17 14:43:33 2001 @@ -126,6 +126,7 @@ #define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */ #define TCP_WINDOW_CLAMP 10 /* Bound advertised window */ #define TCP_INFO 11 /* Information about this connection. */ +#define TCP_QUICKACK 12 /* Block/reenable quick acks */ #define TCPI_OPT_TIMESTAMPS 1 #define TCPI_OPT_SACK 2 diff -u --recursive --new-file v2.4.3/linux/include/linux/tpqic02.h linux/include/linux/tpqic02.h --- v2.4.3/linux/include/linux/tpqic02.h Mon Mar 26 15:50:01 2001 +++ linux/include/linux/tpqic02.h Tue Apr 17 14:45:33 2001 @@ -588,7 +588,7 @@ */ #define TP_REWCLOSE(d) ((MINOR(d)&0x01) == 1) /* rewind bit */ - /* rewind is only done if data has been transfered */ + /* rewind is only done if data has been transferred */ #define TP_DENS(dev) ((MINOR(dev) >> 1) & 0x07) /* tape density */ #define TP_UNIT(dev) ((MINOR(dev) >> 4) & 0x07) /* unit number */ @@ -633,8 +633,8 @@ #define EXC_WP 3 /* Write protected */ #define EXC_EOM 4 /* EOM */ #define EXC_RWA 5 /* read/write abort */ -#define EXC_XBAD 6 /* read error, bad block transfered */ -#define EXC_XFILLER 7 /* read error, filler block transfered */ +#define EXC_XBAD 6 /* read error, bad block transferred */ +#define EXC_XFILLER 7 /* read error, filler block transferred */ #define EXC_NDT 8 /* read error, no data */ #define EXC_NDTEOM 9 /* read error, no data & EOM */ #define EXC_NDTBOM 10 /* read error, no data & BOM */ diff -u --recursive --new-file v2.4.3/linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h --- v2.4.3/linux/include/linux/tty_ldisc.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/tty_ldisc.h Tue Apr 17 14:43:49 2001 @@ -2,22 +2,22 @@ #define _LINUX_TTY_LDISC_H /* - * This structure defines the interface between the tty line discpline + * This structure defines the interface between the tty line discipline * implementation and the tty routines. The following routines can be * defined; unless noted otherwise, they are optional, and can be * filled in with a null pointer. * * int (*open)(struct tty_struct *); * - * This function is called when the line discpline is associated - * with the tty. The line discpline can use this as an + * This function is called when the line discipline is associated + * with the tty. The line discipline can use this as an * opportunity to initialize any state needed by the ldisc routines. * * void (*close)(struct tty_struct *); * - * This function is called when the line discpline is being + * This function is called when the line discipline is being * shutdown, either because the tty is being closed or because - * the tty is being changed to use a new line discpline + * the tty is being changed to use a new line discipline * * void (*flush_buffer)(struct tty_struct *tty); * @@ -28,14 +28,14 @@ * ssize_t (*chars_in_buffer)(struct tty_struct *tty); * * This function returns the number of input characters the line - * iscpline may have queued up to be delivered to the user mode + * discipline may have queued up to be delivered to the user mode * process. * * ssize_t (*read)(struct tty_struct * tty, struct file * file, * unsigned char * buf, size_t nr); * * This function is called when the user requests to read from - * the tty. The line discpline will return whatever characters + * the tty. The line discipline will return whatever characters * it has buffered up for the user. If this function is not * defined, the user will receive an EIO error. * @@ -43,7 +43,7 @@ * const unsigned char * buf, size_t nr); * * This function is called when the user requests to write to the - * tty. The line discpline will deliver the characters to the + * tty. The line discipline will deliver the characters to the * low-level tty device for transmission, optionally performing * some processing on the characters first. If this function is * not defined, the user will receive an EIO error. @@ -54,7 +54,7 @@ * This function is called when the user requests an ioctl which * is not handled by the tty layer or the low-level tty driver. * It is intended for ioctls which affect line discpline - * operation. Not that the search order for ioctls is (1) tty + * operation. Note that the search order for ioctls is (1) tty * layer, (2) tty low-level driver, (3) line discpline. So a * low-level driver can "grab" an ioctl request before the line * discpline has a chance to see it. @@ -62,7 +62,7 @@ * void (*set_termios)(struct tty_struct *tty, struct termios * old); * * This function notifies the line discpline that a change has - * been made to the termios stucture. + * been made to the termios structure. * * int (*poll)(struct tty_struct * tty, struct file * file, * poll_table *wait); diff -u --recursive --new-file v2.4.3/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.4.3/linux/include/linux/videodev.h Fri Mar 2 11:12:10 2001 +++ linux/include/linux/videodev.h Thu Apr 12 12:20:31 2001 @@ -373,6 +373,8 @@ #define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ #define VID_HARDWARE_OV511 27 #define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ +#define VID_HARDWARE_W9966 29 + /* * Initialiser list diff -u --recursive --new-file v2.4.3/linux/include/linux/wait.h linux/include/linux/wait.h --- v2.4.3/linux/include/linux/wait.h Mon Mar 26 15:48:11 2001 +++ linux/include/linux/wait.h Tue Apr 17 14:43:37 2001 @@ -26,6 +26,14 @@ struct __wait_queue { unsigned int flags; #define WQ_FLAG_EXCLUSIVE 0x01 +#define WQ_FLAG_CONTEXT_0 8 /* context specific flag bit numbers */ +#define WQ_FLAG_CONTEXT_1 9 +#define WQ_FLAG_CONTEXT_2 10 +#define WQ_FLAG_CONTEXT_3 11 +#define WQ_FLAG_CONTEXT_4 12 +#define WQ_FLAG_CONTEXT_5 13 +#define WQ_FLAG_CONTEXT_6 14 +#define WQ_FLAG_CONTEXT_7 15 struct task_struct * task; struct list_head task_list; #if WAITQUEUE_DEBUG diff -u --recursive --new-file v2.4.3/linux/include/linux/wanpipe.h linux/include/linux/wanpipe.h --- v2.4.3/linux/include/linux/wanpipe.h Mon Dec 11 13:00:10 2000 +++ linux/include/linux/wanpipe.h Thu Apr 12 12:11:39 2001 @@ -5,13 +5,17 @@ * Author: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * 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. * ============================================================================ +* Nov 3, 2000 Nenad Corbic Added config_id to sdla_t structure. +* Used to determine the protocol running. +* Jul 13, 2000 Nenad Corbic Added SyncPPP Support +* Feb 24, 2000 Nenad Corbic Added support for x25api driver * Oct 04, 1999 Nenad Corbic New CHDLC and FRAME RELAY code, SMP support * Jun 02, 1999 Gideon Hack Added 'update_call_count' for Cisco HDLC * support @@ -35,10 +39,58 @@ #ifndef _WANPIPE_H #define _WANPIPE_H -#include <linux/config.h> +#include <linux/version.h> -#ifdef CONFIG_SMP -#include <asm/spinlock.h> /* Support for SMP Locking */ +#ifndef KERNEL_VERSION + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + + #define LINUX_2_4 + #define netdevice_t struct net_device + + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define stop_net_queue(a) netif_stop_queue(a) + #define start_net_queue(a) netif_start_queue(a) + #define is_queue_stopped(a) netif_queue_stopped(a) + #define wake_net_dev(a) netif_wake_queue(a) + #define is_dev_running(a) netif_running(a) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb_any(a) + + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + + #define LINUX_2_1 + #define netdevice_t struct device + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define stop_net_queue(a) (set_bit(0, &##a->tbusy)) + #define start_net_queue(a) (clear_bit(0,&##a->tbusy)) + #define is_queue_stopped(a) (##a->tbusy) + #define wake_net_dev(a) {clear_bit(0,&##a->tbusy);mark_bh(NET_BH);} + #define is_dev_running(a) (test_bit(0,&##a->start)) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb(a) + +#else + #define LINUX_2_0 + #define netdevice_t struct device + + #define test_and_set_bit set_bit + #define net_ratelimit() 1 + + #define stop_net_queue(a) (set_bit(0, &##a->tbusy)) + #define start_net_queue(a) (clear_bit(0,&##a->tbusy)) + #define is_queue_stopped(a) (##a->tbusy) + #define wake_net_dev(a) {clear_bit(0,&##a->tbusy);mark_bh(NET_BH);} + #define is_dev_running(a) (test_bit(0,(void*)&##a->start)) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb(a,b) + #define spin_lock_init(a) + #define spin_lock(a) + #define spin_unlock(a) #endif #include <linux/wanrouter.h> @@ -49,7 +101,7 @@ #define PACKED __attribute__((packed)) #endif -#define WANPIPE_MAGIC 0x414C4453L /* signatire: 'SDLA' reversed */ +#define WANPIPE_MAGIC 0x414C4453L /* signature: 'SDLA' reversed */ /* IOCTL numbers (up to 16) */ #define WANPIPE_DUMP (ROUTER_USER+0) /* dump adapter's memory */ @@ -64,6 +116,51 @@ #define UDPMGMT_REPLY 0x02 #define UDP_OFFSET 12 +#define MAX_CMD_BUFF 10 +#define MAX_X25_LCN 255 /* Maximum number of x25 channels */ +#define MAX_LCN_NUM 4095 /* Maximum lcn number */ +#define MAX_FT1_RETRY 100 + +#ifdef LINUX_2_4 + #ifndef AF_WANPIPE + #define AF_WANPIPE 25 + #ifndef PF_WANPIPE + #define PF_WANPIPE AF_WANPIPE + #endif + #endif + +#else + #ifndef AF_WANPIPE + #define AF_WANPIPE 24 + #ifndef PF_WANPIPE + #define PF_WANPIPE AF_WANPIPE + #endif + #endif +#endif + + +#define TX_TIMEOUT 5*HZ + +/* General Critical Flags */ +#define SEND_CRIT 0x00 +#define PERI_CRIT 0x01 + +/* Chdlc and PPP polling critical flag */ +#define POLL_CRIT 0x03 + +/* Frame Relay Tx IRQ send critical flag */ +#define SEND_TXIRQ_CRIT 0x02 + +/* Frame Relay ARP critical flag */ +#define ARP_CRIT 0x03 + +/* Bit maps for dynamic interface configuration + * DYN_OPT_ON : turns this option on/off + * DEV_DOWN : device was shutdown by the driver not + * by user + */ +#define DYN_OPT_ON 0x00 +#define DEV_DOWN 0x01 /* * Data structures for IOCTL calls. @@ -197,6 +294,9 @@ } pipe_mgmt_stat_t; +typedef struct { + struct sk_buff *skb; +} bh_data_t, cmd_data_t; #define MAX_LGTH_UDP_MGNT_PKT 2000 @@ -210,11 +310,27 @@ #define WUM_KILL 0x50 #define WUM_EXEC 0x51 +#define WANPIPE 0x00 +#define API 0x01 +#define BRIDGE 0x02 +#define BRIDGE_NODE 0x03 + #ifdef __KERNEL__ /****** Kernel Interface ****************************************************/ #include <linux/sdladrv.h> /* SDLA support module API definitions */ #include <linux/sdlasfm.h> /* SDLA firmware module definitions */ +#include <linux/tqueue.h> +#ifdef LINUX_2_4 + #include <linux/serial.h> + #include <linux/serialP.h> + #include <linux/serial_reg.h> + #include <asm/serial.h> +#endif +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> + #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) @@ -230,6 +346,7 @@ ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\ ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0) + /****** Data Structures *****************************************************/ /* Adapter Data Space. @@ -241,6 +358,7 @@ char devname[WAN_DRVNAME_SZ+1]; /* card name */ sdlahw_t hw; /* hardware configuration */ wan_device_t wandev; /* WAN device data space */ + unsigned open_cnt; /* number of open interfaces */ unsigned long state_tick; /* link state timestamp */ unsigned intr_mode; /* Type of Interrupt Mode */ @@ -248,30 +366,71 @@ char buff_int_mode_unbusy; /* flag for carrying out dev_tint */ char dlci_int_mode_unbusy; /* flag for carrying out dev_tint */ char configured; /* flag for previous configurations */ + unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/ unsigned short irq_dis_poll_count; /* Disabling irqs in poll routine*/ unsigned short force_enable_irq; char TracingEnabled; /* flag for enabling trace */ global_stats_t statistics; /* global statistics */ -#ifdef CONFIG_SMP - spinlock_t lock; /* Support for SMP Locking */ -#endif void* mbox; /* -> mailbox */ void* rxmb; /* -> receive mailbox */ void* flags; /* -> adapter status flags */ void (*isr)(struct sdla* card); /* interrupt service routine */ void (*poll)(struct sdla* card); /* polling routine */ int (*exec)(struct sdla* card, void* u_cmd, void* u_data); - - struct sdla *next; /* Secondary Port Device: Piggibacking */ + /* Used by the listen() system call */ + /* Wanpipe Socket Interface */ + int (*func) (struct sk_buff *, struct sock *); + struct sock *sk; + + /* Shutdown function */ + void (*disable_comm) (struct sdla *card); + + /* Secondary Port Device: Piggibacking */ + struct sdla *next; + + /* TTY driver variables */ + unsigned char tty_opt; + struct tty_struct *tty; + unsigned int tty_minor; + unsigned int tty_open; + unsigned char *tty_buf; + unsigned char *tty_rx; + struct tq_struct tty_task_queue; + union { struct { /****** X.25 specific data **********/ - unsigned lo_pvc; - unsigned hi_pvc; - unsigned lo_svc; - unsigned hi_svc; + u32 lo_pvc; + u32 hi_pvc; + u32 lo_svc; + u32 hi_svc; + netdevice_t *svc_to_dev_map[MAX_X25_LCN]; + netdevice_t *pvc_to_dev_map[MAX_X25_LCN]; + netdevice_t *tx_dev; + netdevice_t *cmd_dev; + u32 no_dev; + volatile u8 *hdlc_buf_status; + u32 tx_interrupts_pending; + u16 timer_int_enabled; + netdevice_t *poll_device; + atomic_t command_busy; + + u16 udp_pkt_lgth; + u32 udp_type; + u8 udp_pkt_src; + u32 udp_lcn; + netdevice_t * udp_dev; + s8 udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + + u8 LAPB_hdlc; /* Option to turn off X25 and run only LAPB */ + u8 logging; /* Option to log call messages */ + u8 oob_on_modem; /* Option to send modem status to the api */ + u16 num_of_ch; /* Number of channels configured by the user */ + + struct tq_struct x25_poll_task; + struct timer_list x25_timer; } x; struct { /****** frame relay specific data ***/ @@ -281,7 +440,7 @@ unsigned rx_top; /* S508 receive buffer end */ unsigned short node_dlci[100]; unsigned short dlci_num; - struct net_device *dlci_to_dev_map[991 + 1]; + netdevice_t *dlci_to_dev_map[991 + 1]; unsigned tx_interrupts_pending; unsigned short timer_int_enabled; unsigned short udp_pkt_lgth; @@ -289,11 +448,13 @@ char udp_pkt_src; unsigned udp_dlci; char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - void* trc_el_base; /* first trace element */ - void* trc_el_last; /* last trace element */ - void *curr_trc_el; /* current trace element */ - unsigned short trc_bfr_space; /* trace buffer space */ + void* trc_el_base; /* first trace element */ + void* trc_el_last; /* last trace element */ + void *curr_trc_el; /* current trace element */ + unsigned short trc_bfr_space; /* trace buffer space */ unsigned char update_comms_stats; + netdevice_t *arp_dev; + spinlock_t if_send_lock; } f; struct /****** PPP-specific data ***********/ { @@ -307,6 +468,10 @@ unsigned rx_top; /* S508 receive buffer end */ char ip_mode; /* STATIC/HOST/PEER IP Mode */ char authenticator; /* Authenticator for PAP/CHAP */ + unsigned char comm_enabled; /* Is comm enabled or not */ + unsigned char peer_route; /* Process Peer Route */ + unsigned long *txbuf_next; /* Next Tx buffer to use */ + unsigned long *rxbuf_next; /* Next Rx buffer to use */ } p; struct /* Cisco HDLC-specific data */ { @@ -324,6 +489,7 @@ void* rxbuf_last; /* -> last Rx buffer */ unsigned rx_base; /* S508 receive buffer base */ unsigned rx_top; /* S508 receive buffer end */ + unsigned char receive_only; /* high speed receivers */ unsigned short protocol_options; unsigned short kpalv_tx; /* Tx kpalv timer */ unsigned short kpalv_rx; /* Rx kpalv timer */ @@ -332,6 +498,19 @@ unsigned state; /* state of the link */ unsigned char api_status; unsigned char update_call_count; + unsigned short api_options; /* for async config */ + unsigned char async_mode; + unsigned short tx_bits_per_char; + unsigned short rx_bits_per_char; + unsigned short stop_bits; + unsigned short parity; + unsigned short break_timer; + unsigned short inter_char_timer; + unsigned short rx_complete_length; + unsigned short xon_char; + unsigned short xoff_char; + unsigned char comm_enabled; /* Is comm enabled or not */ + unsigned char backup; } c; struct { @@ -368,6 +547,18 @@ int bsc_init (sdla_t* card, wandev_conf_t* conf); /* BSC streaming */ int hdlc_init(sdla_t* card, wandev_conf_t* conf); /* HDLC support */ int wpft1_init (sdla_t* card, wandev_conf_t* conf); /* FT1 Config support */ +int wsppp_init (sdla_t* card, wandev_conf_t* conf); /* Sync PPP on top of RAW CHDLC */ + +extern sdla_t * wanpipe_find_card(char *); +extern sdla_t * wanpipe_find_card_num (int); + +extern void wanpipe_queue_tq (struct tq_struct *); +extern void wanpipe_mark_bh (void); +extern void wakeup_sk_bh (netdevice_t *); +extern int change_dev_flags (netdevice_t *, unsigned); +extern unsigned long get_ip_address (netdevice_t *dev, int option); +extern void add_gateway(sdla_t *, netdevice_t *); + #endif /* __KERNEL__ */ #endif /* _WANPIPE_H */ diff -u --recursive --new-file v2.4.3/linux/include/linux/wanrouter.h linux/include/linux/wanrouter.h --- v2.4.3/linux/include/linux/wanrouter.h Mon Mar 26 15:50:18 2001 +++ linux/include/linux/wanrouter.h Tue Apr 17 14:55:49 2001 @@ -5,15 +5,18 @@ * * Author: Nenad Corbic <ncorbic@sangoma.com> * Gideon Hack -* Additions: Arnaldo Carvalho de Melo <acme@conectiva.com.br> +* Additions: Arnaldo Melo * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. * * 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. * ============================================================================ +* Jul 21, 2000 Nenad Corbic Added WAN_FT1_READY State +* Feb 24, 2000 Nenad Corbic Added support for socket based x25api +* Jan 28, 2000 Nenad Corbic Added support for the ASYNC protocol. * Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. * May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t @@ -42,8 +45,24 @@ *****************************************************************************/ #include <linux/version.h> -#if LINUX_VERSION_CODE >= 0x020100 -#define LINUX_2_1 +#ifndef KERNEL_VERSION + #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define LINUX_2_4 + #define netdevice_t struct net_device + #include <linux/spinlock.h> /* Support for SMP Locking */ + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + #define LINUX_2_1 + #define netdevice_t struct device + #include <asm/spinlock.h> /* Support for SMP Locking */ + +#else + #define LINUX_2_0 + #define netdevice_t struct device + #define spinlock_t int #endif #ifndef _ROUTER_H @@ -135,6 +154,10 @@ unsigned r12_r22; /* RESET retransmission limit (0..250) */ unsigned r13_r23; /* CLEAR retransmission limit (0..250) */ unsigned ccitt_compat; /* compatibility mode: 1988/1984/1980 */ + unsigned x25_conf_opt; /* User defined x25 config optoins */ + unsigned char LAPB_hdlc_only; /* Run in HDLC only mode */ + unsigned char logging; /* Control connection logging */ + unsigned char oob_on_modem; /* Whether to send modem status to the user app */ } wan_x25_conf_t; /*---------------------------------------------------------------------------- @@ -182,6 +205,7 @@ unsigned char ignore_cts; /* Ignore these to determine */ unsigned char ignore_keepalive; /* link status (Yes or No) */ unsigned char hdlc_streaming; /* hdlc_streaming mode (Y/N) */ + unsigned char receive_only; /* no transmit buffering (Y/N) */ unsigned keepalive_tx_tmr; /* transmit keepalive timer */ unsigned keepalive_rx_tmr; /* receive keepalive timer */ unsigned keepalive_err_margin; /* keepalive_error_tolerance */ @@ -204,6 +228,7 @@ int dma; /* DMA request level */ char S514_CPU_no[1]; /* S514 PCI adapter CPU number ('A' or 'B') */ unsigned PCI_slot_no; /* S514 PCI adapter slot number */ + char auto_pci_cfg; /* S515 PCI automatic slot detection */ char comm_port; /* Communication Port (PRI=0, SEC=1) */ unsigned bps; /* data transfer rate */ unsigned mtu; /* maximum transmit unit size */ @@ -216,6 +241,12 @@ char station; /* DTE/DCE, primary/secondary, etc. */ char connection; /* permanent/switched/on-demand */ char read_mode; /* read mode: Polling or interrupt */ + char receive_only; /* disable tx buffers */ + char tty; /* Create a fake tty device */ + unsigned tty_major; /* Major number for wanpipe tty device */ + unsigned tty_minor; /* Minor number for wanpipe tty device */ + unsigned tty_mode; /* TTY operation mode SYNC or ASYNC */ + char backup; /* Backup Mode */ unsigned hw_opt[4]; /* other hardware options */ unsigned reserved[4]; /****** arbitrary data ***************/ @@ -237,6 +268,7 @@ #define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */ #define WANCONFIG_BSC 105 /* BiSync Streaming */ #define WANCONFIG_HDLC 106 /* HDLC Support */ +#define WANCONFIG_MPPP 107 /* Multi Port PPP over RAW CHDLC */ /* * Configuration options defines. @@ -288,6 +320,15 @@ #define WANOPT_PPP_HOST 1 #define WANOPT_PPP_PEER 2 +/* ASY Mode Options */ +#define WANOPT_ONE 1 +#define WANOPT_TWO 2 +#define WANOPT_ONE_AND_HALF 3 + +#define WANOPT_NONE 0 +#define WANOPT_ODD 1 +#define WANOPT_EVEN 2 + /* CHDLC Protocol Options */ /* DF Commmented out for now. @@ -303,6 +344,9 @@ #define WANOPT_INTR 0 #define WANOPT_POLL 1 + +#define WANOPT_TTY_SYNC 0 +#define WANOPT_TTY_ASYNC 1 /*---------------------------------------------------------------------------- * WAN Link Status Info (for ROUTER_STAT IOCTL). */ @@ -345,7 +389,15 @@ WAN_CONNECTED, /* link/channel is operational */ WAN_LIMIT, /* for verification only */ WAN_DUALPORT, /* for Dual Port cards */ - WAN_DISCONNECTING /* link/channel is disconnecting */ + WAN_DISCONNECTING, + WAN_FT1_READY /* FT1 Configurator Ready */ +}; + +enum { + WAN_LOCAL_IP, + WAN_POINTOPOINT_IP, + WAN_NETMASK_IP, + WAN_BROADCAST_IP }; /* 'modem_status' masks */ @@ -395,6 +447,27 @@ char clocking; /* external/internal */ unsigned bps; /* data transfer rate */ unsigned mtu; /* maximum transmit unit size */ + unsigned char if_down; /* brind down interface when disconnected */ + unsigned char gateway; /* Is this interface a gateway */ + unsigned char true_if_encoding; /* Set the dev->type to true board protocol */ + + unsigned char asy_data_trans; /* async API options */ + unsigned char rts_hs_for_receive; /* async Protocol options */ + unsigned char xon_xoff_hs_for_receive; + unsigned char xon_xoff_hs_for_transmit; + unsigned char dcd_hs_for_transmit; + unsigned char cts_hs_for_transmit; + unsigned char async_mode; + unsigned tx_bits_per_char; + unsigned rx_bits_per_char; + unsigned stop_bits; + unsigned char parity; + unsigned break_timer; + unsigned inter_char_timer; + unsigned rx_complete_length; + unsigned xon_char; + unsigned xoff_char; + unsigned char receive_only; /* no transmit buffering (Y/N) */ } wanif_conf_t; #ifdef __KERNEL__ @@ -440,30 +513,40 @@ /****** status and statistics *******/ char state; /* device state */ char api_status; /* device api status */ +#if defined(LINUX_2_1) || defined(LINUX_2_4) struct net_device_stats stats; /* interface statistics */ +#else + struct enet_statistics stats; /* interface statistics */ +#endif unsigned reserved[16]; /* reserved for future use */ unsigned long critical; /* critical section flag */ + spinlock_t lock; /* Support for SMP Locking */ + /****** device management methods ***/ int (*setup) (struct wan_device *wandev, wandev_conf_t *conf); int (*shutdown) (struct wan_device *wandev); int (*update) (struct wan_device *wandev); int (*ioctl) (struct wan_device *wandev, unsigned cmd, unsigned long arg); - int (*new_if) (struct wan_device *wandev, struct net_device *dev, + int (*new_if) (struct wan_device *wandev, netdevice_t *dev, wanif_conf_t *conf); - int (*del_if) (struct wan_device *wandev, struct net_device *dev); + int (*del_if) (struct wan_device *wandev, netdevice_t *dev); /****** maintained by the router ****/ struct wan_device* next; /* -> next device */ - struct net_device* dev; /* list of network interfaces */ + netdevice_t* dev; /* list of network interfaces */ unsigned ndev; /* number of interfaces */ +#ifdef LINUX_2_4 struct proc_dir_entry *dent; /* proc filesystem entry */ +#else + struct proc_dir_entry dent; /* proc filesystem entry */ +#endif } wan_device_t; /* Public functions available for device drivers */ extern int register_wan_device(wan_device_t *wandev); extern int unregister_wan_device(char *name); -unsigned short wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev); -int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev); +unsigned short wanrouter_type_trans(struct sk_buff *skb, netdevice_t *dev); +int wanrouter_encapsulate(struct sk_buff *skb, netdevice_t *dev,unsigned short type); /* Proc interface functions. These must not be called by the drivers! */ extern int wanrouter_proc_init(void); @@ -471,6 +554,11 @@ extern int wanrouter_proc_add(wan_device_t *wandev); extern int wanrouter_proc_delete(wan_device_t *wandev); extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); + +extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); + + /* Public Data */ extern wan_device_t *router_devlist; /* list of registered devices */ diff -u --recursive --new-file v2.4.3/linux/include/linux/wavefront.h linux/include/linux/wavefront.h --- v2.4.3/linux/include/linux/wavefront.h Mon Jan 4 11:42:43 1999 +++ linux/include/linux/wavefront.h Thu Apr 12 12:20:31 2001 @@ -31,7 +31,7 @@ member, which has the same semantics anyway. */ -#endif __GNUC__ +#endif /* __GNUC__ */ /***************************** WARNING ******************************** PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO @@ -40,11 +40,11 @@ #ifndef NUM_MIDIKEYS #define NUM_MIDIKEYS 128 -#endif NUM_MIDIKEYS +#endif /* NUM_MIDIKEYS */ #ifndef NUM_MIDICHANNELS #define NUM_MIDICHANNELS 16 -#endif NUM_MIDICHANNELS +#endif /* NUM_MIDICHANNELS */ /* These are very useful/important. the original wavefront interface was developed on a 16 bit system, where sizeof(int) = 2 @@ -667,9 +667,9 @@ /* Allow direct user-space control over FX memory/coefficient data. In theory this could be used to download the FX microprogram, - but it would be a little slower, and involve some wierd code. + but it would be a little slower, and involve some weird code. */ #define WFFX_MEMSET 69 -#endif __wavefront_h__ +#endif /* __wavefront_h__ */ diff -u --recursive --new-file v2.4.3/linux/include/linux/wireless.h linux/include/linux/wireless.h --- v2.4.3/linux/include/linux/wireless.h Mon Mar 26 15:48:17 2001 +++ linux/include/linux/wireless.h Tue Apr 17 14:43:35 2001 @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 9 16.10.99 + * Version : 11 28.3.01 * * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> */ @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 10 +#define WIRELESS_EXT 11 /* * Changes : @@ -111,6 +111,11 @@ * - Add PM modifier : MAX/MIN/RELATIVE * - Add encoding option : IW_ENCODE_NOKEY * - Add TxPower ioctls (work like TxRate) + * + * V10 to V11 + * ---------- + * - Add WE version in range (help backward/forward compatibility) + * - Add retry ioctls (work like PM) */ /* -------------------------- IOCTL LIST -------------------------- */ @@ -153,7 +158,7 @@ * The "flags" member indicate if the ESSID is active or not (promiscuous). */ -/* Other parameters usefull in 802.11 and some other devices */ +/* Other parameters useful in 802.11 and some other devices */ #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ #define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ #define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ @@ -162,6 +167,8 @@ #define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ #define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ #define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ +#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ +#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ /* Encoding stuff (scrambling, hardware security, WEP...) */ #define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ @@ -272,6 +279,16 @@ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ +/* Retry limits and lifetime flags available */ +#define IW_RETRY_ON 0x0000 /* No details... */ +#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ +#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ +#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ +#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */ +#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ +#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ +#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ @@ -288,7 +305,7 @@ /* * For all data larger than 16 octets, we need to use a - * pointer to memory alocated in user space. + * pointer to memory allocated in user space. */ struct iw_point { @@ -385,6 +402,7 @@ struct iw_param rts; /* RTS threshold threshold */ struct iw_param frag; /* Fragmentation threshold */ __u32 mode; /* Operation mode */ + struct iw_param retry; /* Retry limits & lifetime */ struct iw_point encoding; /* Encoding stuff : tokens */ struct iw_param power; /* PM duration/timeout */ @@ -462,6 +480,19 @@ __u16 txpower_capa; /* What options are supported */ __u8 num_txpower; /* Number of entries in the list */ __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ + + /* Wireless Extension version info */ + __u8 we_version_compiled; /* Must be WIRELESS_EXT */ + __u8 we_version_source; /* Last update of source */ + + /* Retry limits and lifetime */ + __u16 retry_capa; /* What retry options are supported */ + __u16 retry_flags; /* How to decode max/min retry limit */ + __u16 r_time_flags; /* How to decode max/min retry life */ + __s32 min_retry; /* Minimal number of retries */ + __s32 max_retry; /* Maximal number of retries */ + __s32 min_r_time; /* Minimal retry lifetime */ + __s32 max_r_time; /* Maximal retry lifetime */ }; /* diff -u --recursive --new-file v2.4.3/linux/include/net/icmp.h linux/include/net/icmp.h --- v2.4.3/linux/include/net/icmp.h Mon Mar 26 15:48:59 2001 +++ linux/include/net/icmp.h Tue Apr 17 14:45:39 2001 @@ -35,9 +35,8 @@ #define ICMP_INC_STATS_BH(field) SNMP_INC_STATS_BH(icmp_statistics, field) #define ICMP_INC_STATS_USER(field) SNMP_INC_STATS_USER(icmp_statistics, field) -extern void icmp_send(struct sk_buff *skb_in, int type, int code, - unsigned long info); -extern int icmp_rcv(struct sk_buff *skb, unsigned short len); +extern void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info); +extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern void icmp_init(struct net_proto_family *ops); diff -u --recursive --new-file v2.4.3/linux/include/net/ip.h linux/include/net/ip.h --- v2.4.3/linux/include/net/ip.h Mon Mar 26 15:48:31 2001 +++ linux/include/net/ip.h Tue Apr 17 14:44:59 2001 @@ -188,11 +188,16 @@ extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst); -static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst) +static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk) { - if (iph->frag_off&__constant_htons(IP_DF)) - iph->id = 0; - else + if (iph->frag_off&__constant_htons(IP_DF)) { + /* This is only to work around buggy Windows95/2000 + * VJ compression implementations. If the ID field + * does not change, they drop every other packet in + * a TCP stream using header compression. + */ + iph->id = ((sk && sk->daddr) ? htons(sk->protinfo.af_inet.id++) : 0); + } else __ip_select_ident(iph, dst); } diff -u --recursive --new-file v2.4.3/linux/include/net/ipip.h linux/include/net/ipip.h --- v2.4.3/linux/include/net/ipip.h Fri Aug 4 18:18:49 2000 +++ linux/include/net/ipip.h Thu Apr 12 12:11:39 2001 @@ -29,8 +29,9 @@ int err; \ int pkt_len = skb->len; \ \ + skb->ip_summed = CHECKSUM_NONE; \ iph->tot_len = htons(skb->len); \ - ip_select_ident(iph, &rt->u.dst); \ + ip_select_ident(iph, &rt->u.dst, NULL); \ ip_send_check(iph); \ \ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, do_ip_send); \ diff -u --recursive --new-file v2.4.3/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.4.3/linux/include/net/ipv6.h Mon Mar 26 15:48:54 2001 +++ linux/include/net/ipv6.h Tue Apr 17 14:45:41 2001 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ipv6.h,v 1.22 2000/09/18 05:54:13 davem Exp $ + * $Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -181,11 +181,11 @@ extern int ip6_call_ra_chain(struct sk_buff *skb, int sel); -extern u8 * ipv6_reassembly(struct sk_buff **skb, u8 *nhptr); +extern int ipv6_reassembly(struct sk_buff **skb, int); -extern u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr); +extern int ipv6_parse_hopopts(struct sk_buff *skb, int); -extern u8 * ipv6_parse_exthdrs(struct sk_buff **skb, u8 *nhptr); +extern int ipv6_parse_exthdrs(struct sk_buff **skb, int); extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); @@ -303,8 +303,10 @@ struct ipv6_txoptions *opt, u8 *proto); -extern u8 * ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, +extern int ipv6_skip_exthdr(struct sk_buff *, int start, u8 *nexthdrp, int len); + +extern int ipv6_ext_hdr(u8 nexthdr); extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr); diff -u --recursive --new-file v2.4.3/linux/include/net/ndisc.h linux/include/net/ndisc.h --- v2.4.3/linux/include/net/ndisc.h Mon Mar 26 15:48:52 2001 +++ linux/include/net/ndisc.h Tue Apr 17 14:45:39 2001 @@ -60,7 +60,7 @@ extern void ndisc_cleanup(void); -extern int ndisc_rcv(struct sk_buff *skb, unsigned long len); +extern int ndisc_rcv(struct sk_buff *skb); extern void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, @@ -91,13 +91,9 @@ extern void igmp6_cleanup(void); -extern int igmp6_event_query(struct sk_buff *skb, - struct icmp6hdr *hdr, - int len); - -extern int igmp6_event_report(struct sk_buff *skb, - struct icmp6hdr *hdr, - int len); +extern int igmp6_event_query(struct sk_buff *skb); + +extern int igmp6_event_report(struct sk_buff *skb); extern void igmp6_cleanup(void); diff -u --recursive --new-file v2.4.3/linux/include/net/protocol.h linux/include/net/protocol.h --- v2.4.3/linux/include/net/protocol.h Mon Mar 26 15:48:11 2001 +++ linux/include/net/protocol.h Tue Apr 17 14:43:35 2001 @@ -36,8 +36,8 @@ /* This is used to register protocols. */ struct inet_protocol { - int (*handler)(struct sk_buff *skb, unsigned short len); - void (*err_handler)(struct sk_buff *skb, unsigned char *dp, int len); + int (*handler)(struct sk_buff *skb); + void (*err_handler)(struct sk_buff *skb, u32 info); struct inet_protocol *next; unsigned char protocol; unsigned char copy:1; @@ -48,12 +48,11 @@ #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct inet6_protocol { - int (*handler)(struct sk_buff *skb, - unsigned long len); + int (*handler)(struct sk_buff *skb); - void (*err_handler)(struct sk_buff *skb, struct ipv6hdr *hdr, + void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, unsigned char *buff, + int type, int code, int offset, __u32 info); struct inet6_protocol *next; unsigned char protocol; diff -u --recursive --new-file v2.4.3/linux/include/net/raw.h linux/include/net/raw.h --- v2.4.3/linux/include/net/raw.h Mon Aug 23 10:01:02 1999 +++ linux/include/net/raw.h Thu Apr 12 12:11:39 2001 @@ -21,7 +21,7 @@ extern struct proto raw_prot; -extern void raw_err(struct sock *, struct sk_buff *); +extern void raw_err(struct sock *, struct sk_buff *, u32 info); extern int raw_rcv(struct sock *, struct sk_buff *); /* Note: v4 ICMP wants to get at this stuff, if you change the diff -u --recursive --new-file v2.4.3/linux/include/net/rawv6.h linux/include/net/rawv6.h --- v2.4.3/linux/include/net/rawv6.h Mon Aug 23 10:01:02 1999 +++ linux/include/net/rawv6.h Thu Apr 12 12:11:39 2001 @@ -8,23 +8,21 @@ extern rwlock_t raw_v6_lock; extern struct sock * ipv6_raw_deliver(struct sk_buff *skb, - int nexthdr, unsigned long len); + int nexthdr); extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, struct in6_addr *loc_addr, struct in6_addr *rmt_addr); extern int rawv6_rcv(struct sock *sk, - struct sk_buff *skb, - unsigned long len); + struct sk_buff *skb); extern void rawv6_err(struct sock *sk, struct sk_buff *skb, - struct ipv6hdr *hdr, struct inet6_skb_parm *opt, int type, int code, - unsigned char *buff, u32 info); + int offset, u32 info); #endif diff -u --recursive --new-file v2.4.3/linux/include/net/sock.h linux/include/net/sock.h --- v2.4.3/linux/include/net/sock.h Mon Mar 26 15:48:31 2001 +++ linux/include/net/sock.h Tue Apr 17 14:44:59 2001 @@ -56,6 +56,10 @@ #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE) #include <net/x25.h> #endif +#if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE) +#include <linux/if_wanpipe.h> +#endif + #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) #include <net/ax25.h> #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) @@ -204,6 +208,7 @@ __u8 mc_loop; /* Loopback */ unsigned recverr : 1, freebind : 1; + __u16 id; /* ID counter for DF pkts */ __u8 pmtudisc; int mc_index; /* Multicast device index */ __u32 mc_addr; @@ -331,6 +336,8 @@ struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} specific */ struct sk_buff *send_head; /* Front of stuff to transmit */ + struct page *sndmsg_page; /* Cached page for sendmsg */ + u32 sndmsg_off; /* Cached offset for sendmsg */ __u32 rcv_wnd; /* Current receiver window */ __u32 rcv_wup; /* rcv_nxt on last window update sent */ @@ -381,8 +388,6 @@ * the first SYN. */ __u32 undo_marker; /* tracking retrans started here. */ int undo_retrans; /* number of undoable retransmissions. */ - __u32 syn_seq; /* Seq of received SYN. */ - __u32 fin_seq; /* Seq of received FIN. */ __u32 urg_seq; /* Seq of received urgent pointer */ __u16 urg_data; /* Saved octet of OOB data and control flags */ __u8 pending; /* Scheduled timer event */ @@ -535,6 +540,7 @@ unsigned char debug; unsigned char rcvtstamp; unsigned char userlocks; + int route_caps; int proc; unsigned long lingertime; @@ -645,6 +651,9 @@ #if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE) struct irda_sock *irda; #endif +#if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE) + struct wanpipe_opt *af_wanpipe; +#endif } protinfo; @@ -833,14 +842,11 @@ int *optlen); extern struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - unsigned long fallback, int noblock, int *errcode); extern void *sock_kmalloc(struct sock *sk, int size, int priority); extern void sock_kfree_s(struct sock *sk, void *mem, int size); -extern int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen); - /* * Functions to fill in entries in struct proto_ops when a protocol * does not implement a particular function. @@ -877,6 +883,10 @@ extern int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma); +extern ssize_t sock_no_sendpage(struct socket *sock, + struct page *page, + int offset, size_t size, + int flags); /* * Default socket callbacks and setup code diff -u --recursive --new-file v2.4.3/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.4.3/linux/include/net/tcp.h Mon Mar 26 15:48:33 2001 +++ linux/include/net/tcp.h Tue Apr 17 14:45:38 2001 @@ -19,10 +19,7 @@ #define _TCP_H #define TCP_DEBUG 1 -#define FASTRETRANS_DEBUG 1 - -/* Be paranoid about data immediately beyond right edge of window. */ -#undef TCP_FORMAL_WINDOW +#define FASTRETRANS_DEBUG 2 /* Cancel timers, when they are not required. */ #undef TCP_CLEAR_TIMERS @@ -182,7 +179,6 @@ __u32 rcv_nxt; __u32 snd_nxt; __u32 rcv_wnd; - __u32 syn_seq; __u32 ts_recent; long ts_recent_stamp; unsigned long ttd; @@ -357,7 +353,7 @@ #define TCP_TWKILL_PERIOD (TCP_TIMEWAIT_LEN/TCP_TWKILL_SLOTS) #define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ -#define TCP_SYNQ_HSIZE 64 /* Size of SYNACK hash table */ +#define TCP_SYNQ_HSIZE 512 /* Size of SYNACK hash table */ #define TCP_PAWS_24DAYS (60 * 60 * 24 * 24) #define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated @@ -632,19 +628,18 @@ extern void __tcp_put_port(struct sock *sk); extern void tcp_inherit_port(struct sock *sk, struct sock *child); -extern void tcp_v4_err(struct sk_buff *skb, - unsigned char *, int); +extern void tcp_v4_err(struct sk_buff *skb, u32); extern void tcp_shutdown (struct sock *sk, int how); -extern int tcp_v4_rcv(struct sk_buff *skb, - unsigned short len); +extern int tcp_v4_rcv(struct sk_buff *skb); extern int tcp_v4_remember_stamp(struct sock *sk); extern int tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw); extern int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size); +extern ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags); extern int tcp_ioctl(struct sock *sk, int cmd, @@ -799,7 +794,7 @@ /* tcp_output.c */ -extern int tcp_write_xmit(struct sock *); +extern int tcp_write_xmit(struct sock *, int nonagle); extern int tcp_retransmit_skb(struct sock *, struct sk_buff *); extern void tcp_xmit_retransmit_queue(struct sock *); extern void tcp_simple_retransmit(struct sock *); @@ -812,6 +807,7 @@ extern int tcp_send_synack(struct sock *); extern int tcp_transmit_skb(struct sock *, struct sk_buff *); extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue, unsigned mss_now); +extern void tcp_push_one(struct sock *, unsigned mss_now); extern void tcp_send_ack(struct sock *sk); extern void tcp_send_delayed_ack(struct sock *sk); @@ -942,6 +938,15 @@ __tcp_fast_path_on(tp, tp->snd_wnd>>tp->snd_wscale); } +static inline void tcp_fast_path_check(struct sock *sk, struct tcp_opt *tp) +{ + if (skb_queue_len(&tp->out_of_order_queue) == 0 && + tp->rcv_wnd && + atomic_read(&sk->rmem_alloc) < sk->rcvbuf && + !tp->urg_data) + tcp_fast_path_on(tp); +} + /* Compute the actual receive window we are currently advertising. * Rcv_nxt can be after the window if our peer push more data * than the offered window. @@ -1084,6 +1089,13 @@ return max(tp->snd_ssthresh, (tp->snd_cwnd>>1)+(tp->snd_cwnd>>2)); } +static inline void tcp_sync_left_out(struct tcp_opt *tp) +{ + if (tp->sack_ok && tp->sacked_out >= tp->packets_out - tp->lost_out) + tp->sacked_out = tp->packets_out - tp->lost_out; + tp->left_out = tp->sacked_out + tp->lost_out; +} + extern void tcp_cwnd_application_limited(struct sock *sk); /* Congestion window validation. (RFC2861) */ @@ -1229,7 +1241,7 @@ if (!tcp_skb_is_last(sk, skb)) nonagle = 1; if (!tcp_snd_test(tp, skb, cur_mss, nonagle) || - tcp_write_xmit(sk)) + tcp_write_xmit(sk, nonagle)) tcp_check_probe_timer(sk, tp); } tcp_cwnd_validate(sk, tp); @@ -1275,7 +1287,7 @@ static __inline__ int __tcp_checksum_complete(struct sk_buff *skb) { - return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)); + return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); } static __inline__ int tcp_checksum_complete(struct sk_buff *skb) @@ -1299,23 +1311,31 @@ * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93) * failed somewhere. Latency? Burstiness? Well, at least now we will * see, why it failed. 8)8) --ANK + * + * NOTE: is this not too big to inline? */ static __inline__ int tcp_prequeue(struct sock *sk, struct sk_buff *skb) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; if (tp->ucopy.task) { - if ((tp->ucopy.memory += skb->truesize) <= (sk->rcvbuf<<1)) { - __skb_queue_tail(&tp->ucopy.prequeue, skb); - if (skb_queue_len(&tp->ucopy.prequeue) == 1) { - wake_up_interruptible(sk->sleep); - if (!tcp_ack_scheduled(tp)) - tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4); + __skb_queue_tail(&tp->ucopy.prequeue, skb); + tp->ucopy.memory += skb->truesize; + if (tp->ucopy.memory > sk->rcvbuf) { + struct sk_buff *skb1; + + if (sk->lock.users) BUG(); + + while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { + sk->backlog_rcv(sk, skb1); + NET_INC_STATS_BH(TCPPrequeueDropped); } - } else { - NET_INC_STATS_BH(TCPPrequeueDropped); - tp->ucopy.memory -= skb->truesize; - __kfree_skb(skb); + + tp->ucopy.memory = 0; + } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { + wake_up_interruptible(sk->sleep); + if (!tcp_ack_scheduled(tp)) + tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4); } return 1; } @@ -1677,19 +1697,40 @@ } } -static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp) +static inline struct sk_buff *tcp_alloc_pskb(struct sock *sk, int size, int mem, int gfp) { - struct sk_buff *skb = alloc_skb(size, gfp); + struct sk_buff *skb = alloc_skb(size+MAX_TCP_HEADER, gfp); if (skb) { + skb->truesize += mem; if (sk->forward_alloc >= (int)skb->truesize || - tcp_mem_schedule(sk, skb->truesize, 0)) + tcp_mem_schedule(sk, skb->truesize, 0)) { + skb_reserve(skb, MAX_TCP_HEADER); return skb; + } __kfree_skb(skb); } else { tcp_enter_memory_pressure(); tcp_moderate_sndbuf(sk); } + return NULL; +} + +static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp) +{ + return tcp_alloc_pskb(sk, size, 0, gfp); +} + +static inline struct page * tcp_alloc_page(struct sock *sk) +{ + if (sk->forward_alloc >= (int)PAGE_SIZE || + tcp_mem_schedule(sk, PAGE_SIZE, 0)) { + struct page *page = alloc_pages(sk->allocation, 0); + if (page) + return page; + } + tcp_enter_memory_pressure(); + tcp_moderate_sndbuf(sk); return NULL; } diff -u --recursive --new-file v2.4.3/linux/include/net/udp.h linux/include/net/udp.h --- v2.4.3/linux/include/net/udp.h Mon Mar 26 15:49:02 2001 +++ linux/include/net/udp.h Tue Apr 17 14:45:00 2001 @@ -59,13 +59,13 @@ extern struct proto udp_prot; -extern void udp_err(struct sk_buff *, unsigned char *, int); +extern void udp_err(struct sk_buff *, u32); extern int udp_connect(struct sock *sk, struct sockaddr *usin, int addr_len); extern int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len); -extern int udp_rcv(struct sk_buff *skb, unsigned short len); +extern int udp_rcv(struct sk_buff *skb); extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int udp_disconnect(struct sock *sk, int flags); diff -u --recursive --new-file v2.4.3/linux/include/scsi/scsi.h linux/include/scsi/scsi.h --- v2.4.3/linux/include/scsi/scsi.h Tue Sep 5 14:08:55 2000 +++ linux/include/scsi/scsi.h Wed Apr 11 19:10:03 2001 @@ -196,8 +196,9 @@ * Here are some scsi specific ioctl commands which are sometimes useful. */ /* These are a few other constants only used by scsi devices */ +/* Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395 */ -#define SCSI_IOCTL_GET_IDLUN 0x5382 +#define SCSI_IOCTL_GET_IDLUN 0x5382 /* conflicts with CDROMAUDIOBUFSIZ */ /* Used to turn on and off tagged queuing for scsi devices */ diff -u --recursive --new-file v2.4.3/linux/include/video/newport.h linux/include/video/newport.h --- v2.4.3/linux/include/video/newport.h Fri Feb 25 10:30:57 2000 +++ linux/include/video/newport.h Thu Apr 12 12:20:31 2001 @@ -486,7 +486,7 @@ * DCBMODE register defines: */ -/* Widht of the data being transfered for each DCBDATA[01] word */ +/* Width of the data being transferred for each DCBDATA[01] word */ #define DCB_DATAWIDTH_4 0x0 #define DCB_DATAWIDTH_1 0x1 #define DCB_DATAWIDTH_2 0x2 diff -u --recursive --new-file v2.4.3/linux/init/main.c linux/init/main.c --- v2.4.3/linux/init/main.c Mon Mar 19 12:26:25 2001 +++ linux/init/main.c Tue Apr 17 15:04:11 2001 @@ -96,7 +96,6 @@ extern void net_notifier_init(void); extern void free_initmem(void); -extern void filesystem_setup(void); #ifdef CONFIG_TC extern void tc_init(void); @@ -722,9 +721,6 @@ start_context_thread(); do_initcalls(); - - /* .. filesystems .. */ - filesystem_setup(); #ifdef CONFIG_IRDA irda_device_init(); /* Must be done after protocol initialization */ diff -u --recursive --new-file v2.4.3/linux/kernel/fork.c linux/kernel/fork.c --- v2.4.3/linux/kernel/fork.c Mon Mar 19 12:35:08 2001 +++ linux/kernel/fork.c Thu Apr 12 12:04:56 2001 @@ -39,7 +39,7 @@ unsigned long flags; wq_write_lock_irqsave(&q->lock, flags); - wait->flags = 0; + wait->flags &= ~WQ_FLAG_EXCLUSIVE; __add_wait_queue(q, wait); wq_write_unlock_irqrestore(&q->lock, flags); } @@ -49,7 +49,7 @@ unsigned long flags; wq_write_lock_irqsave(&q->lock, flags); - wait->flags = WQ_FLAG_EXCLUSIVE; + wait->flags |= WQ_FLAG_EXCLUSIVE; __add_wait_queue_tail(q, wait); wq_write_unlock_irqrestore(&q->lock, flags); } @@ -666,15 +666,17 @@ p->pdeath_signal = 0; /* - * "share" dynamic priority between parent and child, thus the - * total amount of dynamic priorities in the system doesnt change, - * more scheduling fairness. This is only important in the first - * timeslice, on the long run the scheduling behaviour is unchanged. + * Give the parent's dynamic priority entirely to the child. The + * total amount of dynamic priorities in the system doesn't change + * (more scheduling fairness), but the child will run first, which + * is especially useful in avoiding a lot of copy-on-write faults + * if the child for a fork() just wants to do a few simple things + * and then exec(). This is only important in the first timeslice. + * In the long run, the scheduling behavior is unchanged. */ - p->counter = (current->counter + 1) >> 1; - current->counter >>= 1; - if (!current->counter) - current->need_resched = 1; + p->counter = current->counter; + current->counter = 0; + current->need_resched = 1; /* * Ok, add it to the run-queues and make it diff -u --recursive --new-file v2.4.3/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.3/linux/kernel/ksyms.c Fri Mar 2 15:16:59 2001 +++ linux/kernel/ksyms.c Tue Apr 17 14:40:07 2001 @@ -129,7 +129,6 @@ EXPORT_SYMBOL(update_atime); EXPORT_SYMBOL(get_fs_type); EXPORT_SYMBOL(get_super); -EXPORT_SYMBOL(get_empty_super); EXPORT_SYMBOL(getname); EXPORT_SYMBOL(names_cachep); EXPORT_SYMBOL(fput); diff -u --recursive --new-file v2.4.3/linux/kernel/pm.c linux/kernel/pm.c --- v2.4.3/linux/kernel/pm.c Tue Mar 6 19:44:37 2001 +++ linux/kernel/pm.c Fri Apr 6 10:51:19 2001 @@ -22,6 +22,7 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/pm.h> +#include <linux/interrupt.h> int pm_active; @@ -49,6 +50,9 @@ * Add a device to the list of devices that wish to be notified about * power management events. A &pm_dev structure is returned on success, * on failure the return is %NULL. + * + * The callback function will be called in process context and + * it may sleep. */ struct pm_dev *pm_register(pm_dev_t type, @@ -150,6 +154,10 @@ { int status = 0; int prev_state, next_state; + + if (in_interrupt()) + BUG(); + switch (rqst) { case PM_SUSPEND: case PM_RESUME: diff -u --recursive --new-file v2.4.3/linux/kernel/sched.c linux/kernel/sched.c --- v2.4.3/linux/kernel/sched.c Thu Mar 22 09:20:45 2001 +++ linux/kernel/sched.c Thu Apr 12 12:10:25 2001 @@ -739,7 +739,7 @@ state = p->state; if (state & mode) { WQ_NOTE_WAKER(curr); - if (try_to_wake_up(p, sync) && curr->flags && !--nr_exclusive) + if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) break; } } @@ -765,6 +765,75 @@ } } +/* + * wake up processes in the wait queue depending on the state of a context bit in the flags + * - wakes up a process if the specified bit is set in the flags member + * - the context bit is cleared if the process is woken up + * - if the bit number is negative, then the loop stops at the first unset context bit encountered + * - returns the number of processes woken + */ +static inline int __wake_up_ctx_common (wait_queue_head_t *q, + int count, int bit, const int sync) +{ + struct list_head *tmp, *head; + struct task_struct *p; + int stop, woken; + + woken = 0; + stop = bit<0; + if (bit<0) bit = -bit; + + CHECK_MAGIC_WQHEAD(q); + head = &q->task_list; + WQ_CHECK_LIST_HEAD(head); + tmp = head->next; + while (tmp != head) { + wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); + + tmp = tmp->next; + CHECK_MAGIC(curr->__magic); + p = curr->task; + if (!test_and_clear_bit(bit,&curr->flags)) { + if (stop) + break; + continue; + } + + WQ_NOTE_WAKER(curr); + try_to_wake_up(p,sync); + + woken++; + if (woken>=count) + break; + } + + return woken; +} + +int __wake_up_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit) +{ + int woken = 0; + if (q && count) { + unsigned long flags; + wq_read_lock_irqsave(&q->lock, flags); + woken = __wake_up_ctx_common(q, count, bit, 0); + wq_read_unlock_irqrestore(&q->lock, flags); + } + return woken; +} + +int __wake_up_ctx_sync(wait_queue_head_t *q, unsigned int mode, int count, int bit) +{ + int woken = 0; + if (q && count) { + unsigned long flags; + wq_read_lock_irqsave(&q->lock, flags); + woken = __wake_up_ctx_common(q, count, bit, 1); + wq_read_unlock_irqrestore(&q->lock, flags); + } + return woken; +} + #define SLEEP_ON_VAR \ unsigned long flags; \ wait_queue_t wait; \ @@ -1024,9 +1093,11 @@ int i; // Substract non-idle processes running on other CPUs. - for (i = 0; i < smp_num_cpus; i++) - if (aligned_data[i].schedule_data.curr != idle_task(i)) + for (i = 0; i < smp_num_cpus; i++) { + int cpu = cpu_logical_map(i); + if (aligned_data[cpu].schedule_data.curr != idle_task(cpu)) nr_pending--; + } #else // on UP this process is on the runqueue as well nr_pending--; diff -u --recursive --new-file v2.4.3/linux/kernel/sys.c linux/kernel/sys.c --- v2.4.3/linux/kernel/sys.c Tue Mar 6 19:44:37 2001 +++ linux/kernel/sys.c Thu Apr 12 12:20:31 2001 @@ -1089,7 +1089,7 @@ ? -EFAULT : 0; } -#if !defined(__ia64__) && !defined(__s390__) +#if !defined(__ia64__) /* * Back compatibility for getrlimit. Needed for some apps. diff -u --recursive --new-file v2.4.3/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.4.3/linux/kernel/sysctl.c Fri Feb 16 16:02:37 2001 +++ linux/kernel/sysctl.c Thu Apr 12 12:20:31 2001 @@ -77,7 +77,7 @@ #endif #ifdef CONFIG_ARCH_S390 -#ifdef CONFIG_IEEEFPU_EMULATION +#ifdef CONFIG_MATHEMU extern int sysctl_ieee_emulation_warnings; #endif extern int sysctl_userprocess_debug; @@ -242,7 +242,7 @@ &proc_dointvec_minmax, &sysctl_intvec, NULL, &minolduid, &maxolduid}, #ifdef CONFIG_ARCH_S390 -#ifdef CONFIG_IEEEFPU_EMULATION +#ifdef CONFIG_MATHEMU {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings", &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec}, #endif diff -u --recursive --new-file v2.4.3/linux/lib/Makefile linux/lib/Makefile --- v2.4.3/linux/lib/Makefile Fri Dec 29 14:07:24 2000 +++ linux/lib/Makefile Tue Apr 17 17:19:36 2001 @@ -12,6 +12,11 @@ obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o +ifneq ($(CONFIG_RWSEM_GENERIC_SPINLOCK)$(CONFIG_RWSEM_XCHGADD_ALGORITHM),nn) +export-objs += rwsem.o +obj-y += rwsem.o +endif + ifneq ($(CONFIG_HAVE_DEC_LOCK),y) obj-y += dec_and_lock.o endif diff -u --recursive --new-file v2.4.3/linux/lib/cmdline.c linux/lib/cmdline.c --- v2.4.3/linux/lib/cmdline.c Fri Aug 11 19:14:46 2000 +++ linux/lib/cmdline.c Thu Apr 12 12:25:53 2001 @@ -93,9 +93,9 @@ * megabyte, or one gigabyte, respectively. */ -unsigned long memparse (char *ptr, char **retptr) +unsigned long long memparse (char *ptr, char **retptr) { - unsigned long ret = simple_strtoul (ptr, retptr, 0); + unsigned long long ret = simple_strtoull (ptr, retptr, 0); switch (**retptr) { case 'G': diff -u --recursive --new-file v2.4.3/linux/lib/rwsem.c linux/lib/rwsem.c --- v2.4.3/linux/lib/rwsem.c Wed Dec 31 16:00:00 1969 +++ linux/lib/rwsem.c Tue Apr 17 17:19:37 2001 @@ -0,0 +1,152 @@ +/* rwsem.c: R/W semaphores: contention handling functions + * + * Written by David Howells (dhowells@redhat.com). + * Derived from arch/i386/kernel/semaphore.c + */ +#include <linux/rwsem.h> +#include <linux/sched.h> +#include <linux/module.h> + +/* + * wait for the read lock to be granted + * - need to repeal the increment made inline by the caller + * - need to throw a write-lock style spanner into the works (sub 0x00010000 from count) + */ +struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait,tsk); + signed long count; + + rwsemtrace(sem,"Entering rwsem_down_read_failed"); + + /* this waitqueue context flag will be cleared when we are granted the lock */ + __set_bit(RWSEM_WAITING_FOR_READ,&wait.flags); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + + add_wait_queue_exclusive(&sem->wait, &wait); /* FIFO */ + + /* note that we're now waiting on the lock, but no longer actively read-locking */ + count = rwsem_atomic_update(RWSEM_WAITING_BIAS-RWSEM_ACTIVE_BIAS,sem); + + /* if there are no longer active locks, wake the front queued process(es) up + * - it might even be this process, since the waker takes a more active part + */ + if (!(count & RWSEM_ACTIVE_MASK)) + rwsem_wake(sem); + + /* wait to be given the lock */ + for (;;) { + if (!test_bit(RWSEM_WAITING_FOR_READ,&wait.flags)) + break; + schedule(); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + } + + remove_wait_queue(&sem->wait,&wait); + tsk->state = TASK_RUNNING; + + rwsemtrace(sem,"Leaving rwsem_down_read_failed"); + return sem; +} + +/* + * wait for the write lock to be granted + */ +struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait,tsk); + signed long count; + + rwsemtrace(sem,"Entering rwsem_down_write_failed"); + + /* this waitqueue context flag will be cleared when we are granted the lock */ + __set_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + + add_wait_queue_exclusive(&sem->wait, &wait); /* FIFO */ + + /* note that we're waiting on the lock, but no longer actively locking */ + count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem); + + /* if there are no longer active locks, wake the front queued process(es) up + * - it might even be this process, since the waker takes a more active part + */ + if (!(count & RWSEM_ACTIVE_MASK)) + rwsem_wake(sem); + + /* wait to be given the lock */ + for (;;) { + if (!test_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags)) + break; + schedule(); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + } + + remove_wait_queue(&sem->wait,&wait); + tsk->state = TASK_RUNNING; + + rwsemtrace(sem,"Leaving rwsem_down_write_failed"); + return sem; +} + +/* + * handle the lock being released whilst there are processes blocked on it that can now run + * - if we come here, then: + * - the 'active part' of the count (&0x0000ffff) reached zero (but may no longer be zero) + * - the 'waiting part' of the count (&0xffff0000) is negative (and will still be so) + */ +struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) +{ + signed long count; + int woken; + + rwsemtrace(sem,"Entering rwsem_wake"); + + try_again: + /* try to grab an 'activity' marker + * - need to make sure two copies of rwsem_wake() don't do this for two separate processes + * simultaneously + * - be horribly naughty, and only deal with the LSW of the atomic counter + */ + if (rwsem_cmpxchgw(sem,0,RWSEM_ACTIVE_BIAS)!=0) { + rwsemtrace(sem,"rwsem_wake: abort wakeup due to renewed activity"); + goto out; + } + + /* try to grant a single write lock if there's a writer at the front of the queue + * - note we leave the 'active part' of the count incremented by 1 and the waiting part + * incremented by 0x00010000 + */ + if (wake_up_ctx(&sem->wait,1,-RWSEM_WAITING_FOR_WRITE)==1) + goto out; + + /* grant an infinite number of read locks to the readers at the front of the queue + * - note we increment the 'active part' of the count by the number of readers just woken, + * less one for the activity decrement we've already done + */ + woken = wake_up_ctx(&sem->wait,65535,-RWSEM_WAITING_FOR_READ); + if (woken<=0) + goto counter_correction; + + woken *= RWSEM_ACTIVE_BIAS-RWSEM_WAITING_BIAS; + woken -= RWSEM_ACTIVE_BIAS; + rwsem_atomic_update(woken,sem); + + out: + rwsemtrace(sem,"Leaving rwsem_wake"); + return sem; + + /* come here if we need to correct the counter for odd SMP-isms */ + counter_correction: + count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem); + rwsemtrace(sem,"corrected count"); + if (!(count & RWSEM_ACTIVE_MASK)) + goto try_again; + goto out; +} + +EXPORT_SYMBOL(rwsem_down_read_failed); +EXPORT_SYMBOL(rwsem_down_write_failed); +EXPORT_SYMBOL(rwsem_wake); diff -u --recursive --new-file v2.4.3/linux/lib/string.c linux/lib/string.c --- v2.4.3/linux/lib/string.c Tue Mar 6 19:44:37 2001 +++ linux/lib/string.c Fri Apr 6 10:51:19 2001 @@ -350,6 +350,8 @@ * @s: Pointer to the start of the area. * @c: The byte to fill the area with * @count: The size of the area. + * + * Do not use memset() to access IO space, use memset_io() instead. */ void * memset(void * s,int c,size_t count) { @@ -369,11 +371,11 @@ * @dest: Where to copy to * @count: The size of the area. * - * When using copies for I/O remember that bcopy and memcpy are entitled - * to do out of order writes and may well exactly that. + * Note that this is the same as memcpy(), with the arguments reversed. + * memcpy() is the standard, bcopy() is a legacy BSD function. * - * Note that this is the same as memcpy, with the arguments reversed. memcpy - * is the standard, bcopy is a legacy BSD function. + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. */ char * bcopy(const char * src, char * dest, int count) { @@ -393,8 +395,8 @@ * @src: Where to copy from * @count: The size of the area. * - * When using copies for I/O remember that bcopy and memcpy are entitled - * to do out of order writes and may well exactly that. + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. */ void * memcpy(void * dest,const void *src,size_t count) { @@ -414,7 +416,7 @@ * @src: Where to copy from * @count: The size of the area. * - * memmove copes with overlapping areas. + * Unlike memcpy(), memmove() copes with overlapping areas. */ void * memmove(void * dest,const void *src,size_t count) { @@ -439,7 +441,7 @@ #ifndef __HAVE_ARCH_MEMCMP /** - * memmove - Compare two areas of memory + * memcmp - Compare two areas of memory * @cs: One area of memory * @ct: Another area of memory * @count: The size of the area. diff -u --recursive --new-file v2.4.3/linux/lib/vsprintf.c linux/lib/vsprintf.c --- v2.4.3/linux/lib/vsprintf.c Tue Mar 6 19:44:37 2001 +++ linux/lib/vsprintf.c Fri Apr 13 20:26:07 2001 @@ -377,7 +377,7 @@ * sprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @fmt: The format string to use - * @args: Arguments for the format string + * @...: Arguments for the format string */ int sprintf(char * buf, const char *fmt, ...) { diff -u --recursive --new-file v2.4.3/linux/mm/bootmem.c linux/mm/bootmem.c --- v2.4.3/linux/mm/bootmem.c Wed Oct 18 15:18:41 2000 +++ linux/mm/bootmem.c Fri Apr 13 20:26:07 2001 @@ -176,6 +176,7 @@ preferred = 0; goto restart_scan; } + return NULL; found: if (start >= eidx) BUG(); @@ -316,7 +317,8 @@ /* * Whoops, we cannot satisfy the allocation request. */ - BUG(); + printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); + panic("Out of memory"); return NULL; } diff -u --recursive --new-file v2.4.3/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.3/linux/mm/filemap.c Fri Mar 23 14:38:48 2001 +++ linux/mm/filemap.c Fri Apr 13 20:26:07 2001 @@ -108,7 +108,6 @@ if (PageDirty(page)) BUG(); remove_page_from_inode_queue(page); remove_page_from_hash_queue(page); - page->mapping = NULL; } void remove_inode_page(struct page *page) @@ -1062,7 +1061,7 @@ for (;;) { struct page *page, **hash; - unsigned long end_index, nr; + unsigned long end_index, nr, ret; end_index = inode->i_size >> PAGE_CACHE_SHIFT; if (index > end_index) @@ -1110,13 +1109,13 @@ * "pos" here (the actor routine has to update the user buffer * pointers and the remaining count). */ - nr = actor(desc, page, offset, nr); - offset += nr; + ret = actor(desc, page, offset, nr); + offset += ret; index += offset >> PAGE_CACHE_SHIFT; offset &= ~PAGE_CACHE_MASK; page_cache_release(page); - if (nr && desc->count) + if (ret == nr && desc->count) continue; break; @@ -1209,7 +1208,7 @@ UPDATE_ATIME(inode); } -static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) +int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) { char *kaddr; unsigned long left, count = desc->count; @@ -1262,21 +1261,29 @@ static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size) { - char *kaddr; ssize_t written; unsigned long count = desc->count; struct file *file = (struct file *) desc->buf; - mm_segment_t old_fs; if (size > count) size = count; - old_fs = get_fs(); - set_fs(KERNEL_DS); - kaddr = kmap(page); - written = file->f_op->write(file, kaddr + offset, size, &file->f_pos); - kunmap(page); - set_fs(old_fs); + if (file->f_op->writepage) { + written = file->f_op->writepage(file, page, offset, + size, &file->f_pos, size<count); + } else { + char *kaddr; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + kaddr = kmap(page); + written = file->f_op->write(file, kaddr + offset, size, &file->f_pos); + kunmap(page); + + set_fs(old_fs); + } if (written < 0) { desc->error = written; written = 0; @@ -2408,7 +2415,7 @@ return page; } -static inline void remove_suid(struct inode *inode) +inline void remove_suid(struct inode *inode) { unsigned int mode; @@ -2449,9 +2456,13 @@ unsigned long written; long status; int err; + unsigned bytes; cached_page = NULL; + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + down(&inode->i_sem); pos = *ppos; @@ -2474,26 +2485,64 @@ * Check whether we've reached the file size limit. */ err = -EFBIG; + if (limit != RLIM_INFINITY) { if (pos >= limit) { send_sig(SIGXFSZ, current, 0); goto out; } - if (count > limit - pos) { + if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) { + /* send_sig(SIGXFSZ, current, 0); */ + count = limit - (u32)pos; + } + } + + /* + * LFS rule + */ + if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { + if (pos >= MAX_NON_LFS) { send_sig(SIGXFSZ, current, 0); - count = limit - pos; + goto out; + } + if (count > MAX_NON_LFS - (u32)pos) { + /* send_sig(SIGXFSZ, current, 0); */ + count = MAX_NON_LFS - (u32)pos; } } - status = 0; - if (count) { - remove_suid(inode); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - mark_inode_dirty_sync(inode); + /* + * Are we about to exceed the fs block limit ? + * + * If we have written data it becomes a short write + * If we have exceeded without writing data we send + * a signal and give them an EFBIG. + * + * Linus frestrict idea will clean these up nicely.. + */ + + if (pos > inode->i_sb->s_maxbytes) + { + send_sig(SIGXFSZ, current, 0); + err = -EFBIG; + goto out; } + if (pos + count > inode->i_sb->s_maxbytes) + count = inode->i_sb->s_maxbytes - pos; + + if (count == 0) { + err = 0; + goto out; + } + + status = 0; + remove_suid(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty_sync(inode); + while (count) { - unsigned long bytes, index, offset; + unsigned long index, offset; char *kaddr; int deactivate = 1; @@ -2534,7 +2583,7 @@ if (status) goto unlock; kaddr = page_address(page); - status = copy_from_user(kaddr+offset, buf, bytes); + status = __copy_from_user(kaddr+offset, buf, bytes); flush_dcache_page(page); if (status) goto fail_write; diff -u --recursive --new-file v2.4.3/linux/mm/memory.c linux/mm/memory.c --- v2.4.3/linux/mm/memory.c Mon Mar 26 11:02:24 2001 +++ linux/mm/memory.c Thu Apr 5 16:41:17 2001 @@ -274,7 +274,7 @@ */ if (pte_dirty(pte) && page->mapping) set_page_dirty(page); - free_page_and_swap_cache(page); + page_cache_release(page); return 1; } swap_free(pte_to_swp_entry(pte)); @@ -815,6 +815,24 @@ } /* + * Work out if there are any other processes sharing this + * swap cache page. Never mind the buffers. + */ +static inline int exclusive_swap_page(struct page *page) +{ + unsigned int count; + + if (!PageLocked(page)) + BUG(); + if (!PageSwapCache(page)) + return 0; + count = page_count(page) - !!page->buffers; /* 2: us + swap cache */ + count += swap_count(page); /* +1: just swap cache */ + return count == 3; /* =3: total */ +} + + +/* * This routine handles present pages, when users try to write * to a shared page. It is done by copying the page to a new address * and decrementing the shared-page counter for the old page. @@ -853,19 +871,21 @@ * marked dirty). */ switch (page_count(old_page)) { + int can_reuse; + case 3: + if (!old_page->buffers) + break; + /* FallThrough */ case 2: - /* - * Lock the page so that no one can look it up from - * the swap cache, grab a reference and start using it. - * Can not do lock_page, holding page_table_lock. - */ - if (!PageSwapCache(old_page) || TryLockPage(old_page)) + if (!PageSwapCache(old_page)) break; - if (is_page_shared(old_page)) { - UnlockPage(old_page); + if (TryLockPage(old_page)) break; - } + /* Recheck swapcachedness once the page is locked */ + can_reuse = exclusive_swap_page(old_page); UnlockPage(old_page); + if (!can_reuse) + break; /* FallThrough */ case 1: if (PageReserved(old_page)) @@ -903,8 +923,7 @@ return -1; } -static void vmtruncate_list(struct vm_area_struct *mpnt, - unsigned long pgoff, unsigned long partial) +static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff) { do { struct mm_struct *mm = mpnt->vm_mm; @@ -947,7 +966,7 @@ */ void vmtruncate(struct inode * inode, loff_t offset) { - unsigned long partial, pgoff; + unsigned long pgoff; struct address_space *mapping = inode->i_mapping; unsigned long limit; @@ -959,19 +978,15 @@ goto out_unlock; pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1); - if (mapping->i_mmap != NULL) - vmtruncate_list(mapping->i_mmap, pgoff, partial); + vmtruncate_list(mapping->i_mmap, pgoff); if (mapping->i_mmap_shared != NULL) - vmtruncate_list(mapping->i_mmap_shared, pgoff, partial); + vmtruncate_list(mapping->i_mmap_shared, pgoff); out_unlock: spin_unlock(&mapping->i_shared_lock); truncate_inode_pages(mapping, offset); - if (inode->i_op && inode->i_op->truncate) - inode->i_op->truncate(inode); - return; + goto out_truncate; do_expand: limit = current->rlim[RLIMIT_FSIZE].rlim_cur; @@ -986,8 +1001,13 @@ } } inode->i_size = offset; - if (inode->i_op && inode->i_op->truncate) + +out_truncate: + if (inode->i_op && inode->i_op->truncate) { + lock_kernel(); inode->i_op->truncate(inode); + unlock_kernel(); + } out: return; } @@ -1077,7 +1097,7 @@ pte = mk_pte(page, vma->vm_page_prot); swap_free(entry); - if (write_access && !is_page_shared(page)) + if (write_access && exclusive_swap_page(page)) pte = pte_mkwrite(pte_mkdirty(pte)); UnlockPage(page); diff -u --recursive --new-file v2.4.3/linux/mm/mmap.c linux/mm/mmap.c --- v2.4.3/linux/mm/mmap.c Wed Mar 28 12:55:34 2001 +++ linux/mm/mmap.c Fri Apr 13 20:15:55 2001 @@ -64,6 +64,15 @@ free += atomic_read(&page_cache_size); free += nr_free_pages(); free += nr_swap_pages; + + /* + * This double-counts: the nrpages are both in the page-cache + * and in the swapper space. At the same time, this compensates + * for the swap-space over-allocation (ie "nr_swap_pages" being + * too small. + */ + free += swapper_space.nrpages; + /* * The code below doesn't account for free space in the inode * and dentry slab cache, slab cache fragmentation, inodes and @@ -224,14 +233,9 @@ /* Obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. */ - if (flags & MAP_FIXED) { - if (addr & ~PAGE_MASK) - return -EINVAL; - } else { - addr = get_unmapped_area(addr, len); - if (!addr) - return -ENOMEM; - } + addr = get_unmapped_area(file, addr, len, pgoff, flags); + if (addr & ~PAGE_MASK) + return addr; /* Do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open @@ -384,30 +388,53 @@ } /* Get an address range which is currently unmapped. - * For mmap() without MAP_FIXED and shmat() with addr=0. - * Return value 0 means ENOMEM. + * For shmat() with addr=0. + * + * Ugly calling convention alert: + * Return value with the low bits set means error value, + * ie + * if (ret & ~PAGE_MASK) + * error = ret; + * + * This function "knows" that -ENOMEM has the bits set. */ #ifndef HAVE_ARCH_UNMAPPED_AREA -unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +static inline unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct vm_area_struct * vmm; + struct vm_area_struct *vma; if (len > TASK_SIZE) - return 0; + return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; addr = PAGE_ALIGN(addr); - for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ + for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) - return 0; - if (!vmm || addr + len <= vmm->vm_start) + return -ENOMEM; + if (!vma || addr + len <= vma->vm_start) return addr; - addr = vmm->vm_end; + addr = vma->vm_end; } } -#endif +#else +extern unsigned long arch_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); +#endif + +unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) +{ + if (flags & MAP_FIXED) { + if (addr & ~PAGE_MASK) + return -EINVAL; + return addr; + } + + if (file && file->f_op && file->f_op->get_unmapped_area) + return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags); + + return arch_get_unmapped_area(file, addr, len, pgoff, flags); +} #define vm_avl_empty (struct vm_area_struct *) NULL diff -u --recursive --new-file v2.4.3/linux/mm/mremap.c linux/mm/mremap.c --- v2.4.3/linux/mm/mremap.c Mon Mar 19 17:17:43 2001 +++ linux/mm/mremap.c Fri Apr 13 15:17:21 2001 @@ -276,8 +276,13 @@ ret = -ENOMEM; if (flags & MREMAP_MAYMOVE) { if (!(flags & MREMAP_FIXED)) { - new_addr = get_unmapped_area(0, new_len); - if (!new_addr) + unsigned long map_flags = 0; + if (vma->vm_flags & VM_SHARED) + map_flags |= MAP_SHARED; + + new_addr = get_unmapped_area(vma->vm_file, 0, new_len, vma->vm_pgoff, map_flags); + ret = new_addr; + if (new_addr & ~PAGE_MASK) goto out; } ret = move_vma(vma, addr, old_len, new_len, new_addr); diff -u --recursive --new-file v2.4.3/linux/mm/shmem.c linux/mm/shmem.c --- v2.4.3/linux/mm/shmem.c Fri Mar 2 15:16:59 2001 +++ linux/mm/shmem.c Thu Apr 12 12:25:53 2001 @@ -1,5 +1,5 @@ /* - * Resizable simple shmem filesystem for Linux. + * Resizable virtual memory filesystem for Linux. * * Copyright (C) 2000 Linus Torvalds. * 2000 Transmeta Corp. @@ -9,14 +9,12 @@ */ /* - * This shared memory handling is heavily based on the ramfs. It - * extends the ramfs by the ability to use swap which would makes it a - * completely usable filesystem. - * - * But read and write are not supported (yet) - * + * This virtual memory filesystem is heavily based on the ramfs. It + * extends ramfs by the ability to use swap and honor resource limits + * which makes it a completely usable filesystem. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> @@ -31,7 +29,8 @@ #include <asm/uaccess.h> -#define SHMEM_MAGIC 0x01021994 +/* This magic number is used in glibc for posix shared memory */ +#define TMPFS_MAGIC 0x01021994 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long)) #define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT) @@ -42,33 +41,74 @@ static struct inode_operations shmem_inode_operations; static struct file_operations shmem_dir_operations; static struct inode_operations shmem_dir_inode_operations; -static struct vm_operations_struct shmem_shared_vm_ops; -static struct vm_operations_struct shmem_private_vm_ops; +static struct inode_operations shmem_symlink_inode_operations; +static struct vm_operations_struct shmem_vm_ops; LIST_HEAD (shmem_inodes); static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED; +#define BLOCKS_PER_PAGE (PAGE_SIZE/512) + +/* + * shmem_recalc_inode - recalculate the size of an inode + * + * @inode: inode to recalc + * + * We have to calculate the free blocks since the mm can drop pages + * behind our back + * + * But we know that normally + * inodes->i_blocks/BLOCKS_PER_PAGE == + * inode->i_mapping->nrpages + info->swapped + * + * So the mm freed + * inodes->i_blocks/BLOCKS_PER_PAGE - + * (inode->i_mapping->nrpages + info->swapped) + * + * It has to be called with the spinlock held. + */ + +static void shmem_recalc_inode(struct inode * inode) +{ + unsigned long freed; + + freed = (inode->i_blocks/BLOCKS_PER_PAGE) - + (inode->i_mapping->nrpages + inode->u.shmem_i.swapped); + if (freed){ + struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb; + inode->i_blocks -= freed*BLOCKS_PER_PAGE; + spin_lock (&info->stat_lock); + info->free_blocks += freed; + spin_unlock (&info->stat_lock); + } +} + static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index) { + unsigned long offset; + if (index < SHMEM_NR_DIRECT) return info->i_direct+index; index -= SHMEM_NR_DIRECT; - if (index >= ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) - return NULL; + offset = index % ENTRIES_PER_PAGE; + index /= ENTRIES_PER_PAGE; + + if (index >= ENTRIES_PER_PAGE) + return ERR_PTR(-EFBIG); if (!info->i_indirect) { info->i_indirect = (swp_entry_t **) get_zeroed_page(GFP_USER); if (!info->i_indirect) - return NULL; + return ERR_PTR(-ENOMEM); } - if(!(info->i_indirect[index/ENTRIES_PER_PAGE])) { - info->i_indirect[index/ENTRIES_PER_PAGE] = (swp_entry_t *) get_zeroed_page(GFP_USER); - if (!info->i_indirect[index/ENTRIES_PER_PAGE]) - return NULL; + if(!(info->i_indirect[index])) { + info->i_indirect[index] = (swp_entry_t *) get_zeroed_page(GFP_USER); + if (!info->i_indirect[index]) + return ERR_PTR(-ENOMEM); } - return info->i_indirect[index/ENTRIES_PER_PAGE]+index%ENTRIES_PER_PAGE; + return info->i_indirect[index]+offset; } static int shmem_free_swp(swp_entry_t *dir, unsigned int count) @@ -81,13 +121,13 @@ if (!ptr->val) continue; entry = *ptr; - swap_free (entry); *ptr = (swp_entry_t){0}; freed++; - if (!(page = lookup_swap_cache(entry))) - continue; - delete_from_swap_cache(page); - page_cache_release(page); + if ((page = lookup_swap_cache(entry)) != NULL) { + delete_from_swap_cache(page); + page_cache_release(page); + } + swap_free (entry); } return freed; } @@ -98,7 +138,6 @@ * @dir: pointer to swp_entries * @size: number of entries in dir * @start: offset to start from - * @inode: inode for statistics * @freed: counter for freed pages * * It frees the swap entries from dir+start til dir+size @@ -108,7 +147,7 @@ static unsigned long shmem_truncate_part (swp_entry_t * dir, unsigned long size, - unsigned long start, struct inode * inode, unsigned long *freed) { + unsigned long start, unsigned long *freed) { if (start > size) return start - size; if (dir) @@ -117,56 +156,28 @@ return 0; } -/* - * shmem_recalc_inode - recalculate the size of an inode - * - * @inode: inode to recalc - * - * We have to calculate the free blocks since the mm can drop pages - * behind our back - * - * But we know that normally - * inodes->i_blocks == inode->i_mapping->nrpages + info->swapped - * - * So the mm freed - * inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped) - * - * It has to be called with the spinlock held. - */ - -static void shmem_recalc_inode(struct inode * inode) -{ - unsigned long freed; - - freed = inode->i_blocks - - (inode->i_mapping->nrpages + inode->u.shmem_i.swapped); - if (freed){ - struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb; - inode->i_blocks -= freed; - spin_lock (&info->stat_lock); - info->free_blocks += freed; - spin_unlock (&info->stat_lock); - } -} - static void shmem_truncate (struct inode * inode) { int clear_base; - unsigned long start; + unsigned long index, start; unsigned long freed = 0; - swp_entry_t **base, **ptr; + swp_entry_t **base, **ptr, **last; struct shmem_inode_info * info = &inode->u.shmem_i; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; spin_lock (&info->lock); - start = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if (index > info->max_index) + goto out; - start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, start, inode, &freed); + start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, index, &freed); if (!(base = info->i_indirect)) - goto out;; + goto out; clear_base = 1; - for (ptr = base; ptr < base + ENTRIES_PER_PAGE; ptr++) { + last = base + ((info->max_index - SHMEM_NR_DIRECT + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE); + for (ptr = base; ptr < last; ptr++) { if (!start) { if (!*ptr) continue; @@ -176,16 +187,16 @@ continue; } clear_base = 0; - start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, inode, &freed); + start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, &freed); } - if (!clear_base) - goto out; - - free_page ((unsigned long)base); - info->i_indirect = 0; + if (clear_base) { + free_page ((unsigned long)base); + info->i_indirect = 0; + } out: + info->max_index = index; info->swapped -= freed; shmem_recalc_inode(inode); spin_unlock (&info->lock); @@ -207,15 +218,29 @@ } /* - * Move the page from the page cache to the swap cache + * Move the page from the page cache to the swap cache. + * + * The page lock prevents multiple occurences of shmem_writepage at + * once. We still need to guard against racing with + * shmem_getpage_locked(). */ static int shmem_writepage(struct page * page) { - int error; + int error = 0; struct shmem_inode_info *info; swp_entry_t *entry, swap; + struct inode *inode; - info = &page->mapping->host->u.shmem_i; + if (!PageLocked(page)) + BUG(); + + /* Only move to the swap cache if there are no other users of + * the page. */ + if (atomic_read(&page->count) > 2) + goto out; + + inode = page->mapping->host; + info = &inode->u.shmem_i; swap = __get_swap_page(2); if (!swap.val) { set_page_dirty(page); @@ -224,17 +249,15 @@ } spin_lock(&info->lock); - shmem_recalc_inode(page->mapping->host); - entry = shmem_swp_entry (info, page->index); - if (!entry) /* this had been allocted on page allocation */ + entry = shmem_swp_entry(info, page->index); + if (IS_ERR(entry)) /* this had been allocted on page allocation */ BUG(); + shmem_recalc_inode(page->mapping->host); error = -EAGAIN; - if (entry->val) { - __swap_free(swap, 2); - goto out; - } + if (entry->val) + BUG(); - *entry = swap; + *entry = swap; error = 0; /* Remove the from the page cache */ lru_cache_del(page); @@ -245,97 +268,185 @@ page_cache_release(page); set_page_dirty(page); info->swapped++; -out: + spin_unlock(&info->lock); +out: UnlockPage(page); return error; } /* - * shmem_nopage - either get the page from swap or allocate a new one + * shmem_getpage_locked - either get the page from swap or allocate a new one * * If we allocate a new one we do not mark it dirty. That's up to the * vm. If we swap it in we mark it dirty since we also free the swap * entry since a page cannot live in both the swap and page cache + * + * Called with the inode locked, so it cannot race with itself, but we + * still need to guard against racing with shm_writepage(), which might + * be trying to move the page to the swap cache as we run. */ -struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share) +static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx) { - unsigned long size; - struct page * page; - unsigned int idx; - swp_entry_t *entry; - struct inode * inode = vma->vm_file->f_dentry->d_inode; struct address_space * mapping = inode->i_mapping; struct shmem_inode_info *info; + struct page * page; + swp_entry_t *entry; - idx = (address - vma->vm_start) >> PAGE_SHIFT; - idx += vma->vm_pgoff; - - down (&inode->i_sem); - size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - page = NOPAGE_SIGBUS; - if ((idx >= size) && (vma->vm_mm == current->mm)) - goto out; + info = &inode->u.shmem_i; - /* retry, we may have slept */ - page = __find_lock_page(mapping, idx, page_hash (mapping, idx)); +repeat: + page = find_lock_page(mapping, idx); if (page) - goto cached_page; + return page; - info = &inode->u.shmem_i; entry = shmem_swp_entry (info, idx); - if (!entry) - goto oom; + if (IS_ERR(entry)) + return (void *)entry; + spin_lock (&info->lock); - shmem_recalc_inode(inode); - spin_unlock (&info->lock); + + /* The shmem_swp_entry() call may have blocked, and + * shmem_writepage may have been moving a page between the page + * cache and swap cache. We need to recheck the page cache + * under the protection of the info->lock spinlock. */ + + page = __find_get_page(mapping, idx, page_hash(mapping, idx)); + if (page) { + if (TryLockPage(page)) + goto wait_retry; + spin_unlock (&info->lock); + return page; + } + if (entry->val) { unsigned long flags; /* Look it up and read it in.. */ - page = lookup_swap_cache(*entry); + page = __find_get_page(&swapper_space, entry->val, + page_hash(&swapper_space, entry->val)); if (!page) { + spin_unlock (&info->lock); lock_kernel(); swapin_readahead(*entry); page = read_swap_cache(*entry); unlock_kernel(); if (!page) - goto oom; + return ERR_PTR(-ENOMEM); + if (!Page_Uptodate(page)) { + page_cache_release(page); + return ERR_PTR(-EIO); + } + + /* Too bad we can't trust this page, because we + * dropped the info->lock spinlock */ + page_cache_release(page); + goto repeat; } /* We have to this with page locked to prevent races */ - spin_lock (&info->lock); + if (TryLockPage(page)) + goto wait_retry; + + if (swap_count(page) > 2) + BUG(); + swap_free(*entry); - lock_page(page); - delete_from_swap_cache_nolock(page); *entry = (swp_entry_t) {0}; + delete_from_swap_cache_nolock(page); flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1)); page->flags = flags | (1 << PG_dirty); add_to_page_cache_locked(page, mapping, idx); info->swapped--; spin_unlock (&info->lock); } else { + spin_unlock (&info->lock); spin_lock (&inode->i_sb->u.shmem_sb.stat_lock); if (inode->i_sb->u.shmem_sb.free_blocks == 0) goto no_space; inode->i_sb->u.shmem_sb.free_blocks--; spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); - /* Ok, get a new page */ + + /* Ok, get a new page. We don't have to worry about the + * info->lock spinlock here: we cannot race against + * shm_writepage because we have already verified that + * there is no page present either in memory or in the + * swap cache, so we are guaranteed to be populating a + * new shm entry. The inode semaphore we already hold + * is enough to make this atomic. */ page = page_cache_alloc(mapping); if (!page) - goto oom; - clear_user_highpage(page, address); - inode->i_blocks++; + return ERR_PTR(-ENOMEM); + clear_highpage(page); + inode->i_blocks += BLOCKS_PER_PAGE; add_to_page_cache (page, mapping, idx); } + /* We have the page */ - SetPageUptodate (page); + SetPageUptodate(page); if (info->locked) page_cache_get(page); + return page; +no_space: + spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); + return ERR_PTR(-ENOSPC); -cached_page: - UnlockPage (page); - up(&inode->i_sem); +wait_retry: + spin_unlock (&info->lock); + wait_on_page(page); + page_cache_release(page); + goto repeat; +} + +static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr) +{ + struct address_space * mapping = inode->i_mapping; + int error; + + *ptr = NOPAGE_SIGBUS; + if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE) + return -EFAULT; + + *ptr = __find_get_page(mapping, idx, page_hash(mapping, idx)); + if (*ptr) { + if (Page_Uptodate(*ptr)) + return 0; + page_cache_release(*ptr); + } + + down (&inode->i_sem); + /* retest we may have slept */ + if (inode->i_size < (loff_t) idx * PAGE_CACHE_SIZE) + goto sigbus; + *ptr = shmem_getpage_locked(inode, idx); + if (IS_ERR (*ptr)) + goto failed; + UnlockPage(*ptr); + up (&inode->i_sem); + return 0; +failed: + up (&inode->i_sem); + error = PTR_ERR(*ptr); + *ptr = NOPAGE_OOM; + if (error != -EFBIG) + *ptr = NOPAGE_SIGBUS; + return error; +sigbus: + *ptr = NOPAGE_SIGBUS; + return -EFAULT; +} + +struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share) +{ + struct page * page; + unsigned int idx; + struct inode * inode = vma->vm_file->f_dentry->d_inode; + + idx = (address - vma->vm_start) >> PAGE_SHIFT; + idx += vma->vm_pgoff; + + if (shmem_getpage(inode, idx, &page)) + return page; if (no_share) { struct page *new_page = page_cache_alloc(inode->i_mapping); @@ -351,13 +462,45 @@ flush_page_to_ram (page); return(page); -no_space: - spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); -oom: - page = NOPAGE_OOM; -out: +} + +void shmem_lock(struct file * file, int lock) +{ + struct inode * inode = file->f_dentry->d_inode; + struct shmem_inode_info * info = &inode->u.shmem_i; + struct page * page; + unsigned long idx, size; + + if (info->locked == lock) + return; + down(&inode->i_sem); + info->locked = lock; + size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + for (idx = 0; idx < size; idx++) { + page = find_lock_page(inode->i_mapping, idx); + if (!page) + continue; + if (!lock) { + /* release the extra count and our reference */ + page_cache_release(page); + page_cache_release(page); + } + UnlockPage(page); + } up(&inode->i_sem); - return page; +} + +static int shmem_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct vm_operations_struct * ops; + struct inode *inode = file->f_dentry->d_inode; + + ops = &shmem_vm_ops; + if (!inode->i_sb || !S_ISREG(inode->i_mode)) + return -EACCES; + UPDATE_ATIME(inode); + vma->vm_ops = ops; + return 0; } struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev) @@ -392,11 +535,13 @@ inode->i_fop = &shmem_file_operations; break; case S_IFDIR: + inode->i_nlink++; inode->i_op = &shmem_dir_inode_operations; inode->i_fop = &shmem_dir_operations; break; case S_IFLNK: - BUG(); + inode->i_op = &shmem_symlink_inode_operations; + break; } spin_lock (&shmem_ilock); list_add (&inode->u.shmem_i.list, &shmem_inodes); @@ -405,49 +550,242 @@ return inode; } +#ifdef CONFIG_TMPFS +static ssize_t +shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + loff_t pos; + struct page *page; + unsigned long written; + long status; + int err; + + + down(&inode->i_sem); + + pos = *ppos; + err = -EINVAL; + if (pos < 0) + goto out; + + err = file->f_error; + if (err) { + file->f_error = 0; + goto out; + } + + written = 0; + + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + /* + * Check whether we've reached the file size limit. + */ + err = -EFBIG; + if (limit != RLIM_INFINITY) { + if (pos >= limit) { + send_sig(SIGXFSZ, current, 0); + goto out; + } + if (count > limit - pos) { + send_sig(SIGXFSZ, current, 0); + count = limit - pos; + } + } + + status = 0; + if (count) { + remove_suid(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + } + + while (count) { + unsigned long bytes, index, offset; + char *kaddr; + int deactivate = 1; + + /* + * Try to find the page in the cache. If it isn't there, + * allocate a free page. + */ + offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ + index = pos >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; + if (bytes > count) { + bytes = count; + deactivate = 0; + } + + /* + * Bring in the user page that we will copy from _first_. + * Otherwise there's a nasty deadlock on copying from the + * same page as we're writing to, without it being marked + * up-to-date. + */ + { volatile unsigned char dummy; + __get_user(dummy, buf); + __get_user(dummy, buf+bytes-1); + } + + page = shmem_getpage_locked(inode, index); + status = PTR_ERR(page); + if (IS_ERR(page)) + break; + + /* We have exclusive IO access to the page.. */ + if (!PageLocked(page)) { + PAGE_BUG(page); + } + + kaddr = kmap(page); +// can this do a truncated write? cr + status = copy_from_user(kaddr+offset, buf, bytes); + kunmap(page); + if (status) + goto fail_write; + + flush_dcache_page(page); + if (bytes > 0) { + SetPageDirty(page); + written += bytes; + count -= bytes; + pos += bytes; + buf += bytes; + if (pos > inode->i_size) + inode->i_size = pos; + if (inode->u.shmem_i.max_index <= index) + inode->u.shmem_i.max_index = index+1; + + } +unlock: + /* Mark it unlocked again and drop the page.. */ + UnlockPage(page); + if (deactivate) + deactivate_page(page); + page_cache_release(page); + + if (status < 0) + break; + } + *ppos = pos; + + err = written ? written : status; +out: + up(&inode->i_sem); + return err; +fail_write: + status = -EFAULT; + ClearPageUptodate(page); + kunmap(page); + goto unlock; +} + +static void do_shmem_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + unsigned long index, offset; + int nr = 1; + + index = *ppos >> PAGE_CACHE_SHIFT; + offset = *ppos & ~PAGE_CACHE_MASK; + + while (nr && desc->count) { + struct page *page; + unsigned long end_index, nr; + + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + if (index > end_index) + break; + nr = PAGE_CACHE_SIZE; + if (index == end_index) { + nr = inode->i_size & ~PAGE_CACHE_MASK; + if (nr <= offset) + break; + } + + nr = nr - offset; + + if ((desc->error = shmem_getpage(inode, index, &page))) + break; + + if (mapping->i_mmap_shared != NULL) + flush_dcache_page(page); + + /* + * Ok, we have the page, and it's up-to-date, so + * now we can copy it to user space... + * + * The actor routine returns how many bytes were actually used.. + * NOTE! This may not be the same as how much of a user buffer + * we filled up (we may be padding etc), so we can only update + * "pos" here (the actor routine has to update the user buffer + * pointers and the remaining count). + */ + nr = file_read_actor(desc, page, offset, nr); + offset += nr; + index += offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + + page_cache_release(page); + } + + *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset; + UPDATE_ATIME(inode); +} + +static ssize_t shmem_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos) +{ + ssize_t retval; + + retval = -EFAULT; + if (access_ok(VERIFY_WRITE, buf, count)) { + retval = 0; + + if (count) { + read_descriptor_t desc; + + desc.written = 0; + desc.count = count; + desc.buf = buf; + desc.error = 0; + do_shmem_file_read(filp, ppos, &desc); + + retval = desc.written; + if (!retval) + retval = desc.error; + } + } + return retval; +} + static int shmem_statfs(struct super_block *sb, struct statfs *buf) { - buf->f_type = SHMEM_MAGIC; + buf->f_type = TMPFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; spin_lock (&sb->u.shmem_sb.stat_lock); - if (sb->u.shmem_sb.max_blocks != ULONG_MAX || - sb->u.shmem_sb.max_inodes != ULONG_MAX) { + if (sb->u.shmem_sb.max_blocks == ULONG_MAX) { + /* + * This is only a guestimate and not honoured. + * We need it to make some programs happy which like to + * test the free space of a file system. + */ + buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages); + buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks; + } else { buf->f_blocks = sb->u.shmem_sb.max_blocks; buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks; - buf->f_files = sb->u.shmem_sb.max_inodes; - buf->f_ffree = sb->u.shmem_sb.free_inodes; } + buf->f_files = sb->u.shmem_sb.max_inodes; + buf->f_ffree = sb->u.shmem_sb.free_inodes; spin_unlock (&sb->u.shmem_sb.stat_lock); buf->f_namelen = 255; return 0; } -void shmem_lock(struct file * file, int lock) -{ - struct inode * inode = file->f_dentry->d_inode; - struct shmem_inode_info * info = &inode->u.shmem_i; - struct page * page; - unsigned long idx, size; - - if (info->locked == lock) - return; - down(&inode->i_sem); - info->locked = lock; - size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - for (idx = 0; idx < size; idx++) { - page = find_lock_page(inode->i_mapping, idx); - if (!page) - continue; - if (!lock) { - /* release the extra count and our reference */ - page_cache_release(page); - page_cache_release(page); - } - UnlockPage(page); - } - up(&inode->i_sem); -} - /* * Lookup the data. This is trivial - if the dentry didn't already * exist, we know it is negative. @@ -466,6 +804,7 @@ struct inode * inode = shmem_get_inode(dir->i_sb, mode, dev); int error = -ENOSPC; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; if (inode) { d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ @@ -476,7 +815,12 @@ static int shmem_mkdir(struct inode * dir, struct dentry * dentry, int mode) { - return shmem_mknod(dir, dentry, mode | S_IFDIR, 0); + int error; + + if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0))) + return error; + dir->i_nlink++; + return 0; } static int shmem_create(struct inode *dir, struct dentry *dentry, int mode) @@ -494,6 +838,7 @@ if (S_ISDIR(inode->i_mode)) return -EPERM; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; inode->i_nlink++; atomic_inc(&inode->i_count); /* New dentry reference */ dget(dentry); /* Extra pinning count for the created dentry */ @@ -534,26 +879,24 @@ return 1; } -/* - * This works for both directories and regular files. - * (non-directories will always have empty subdirs) - */ static int shmem_unlink(struct inode * dir, struct dentry *dentry) { - int retval = -ENOTEMPTY; + struct inode *inode = dentry->d_inode; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink--; + dput(dentry); /* Undo the count from "create" - this does all the work */ + return 0; +} - if (shmem_empty(dentry)) { - struct inode *inode = dentry->d_inode; +static int shmem_rmdir(struct inode * dir, struct dentry *dentry) +{ + if (!shmem_empty(dentry)) + return -ENOTEMPTY; - inode->i_nlink--; - dput(dentry); /* Undo the count from "create" - this does all the work */ - retval = 0; - } - return retval; + dir->i_nlink--; + return shmem_unlink(dir, dentry); } -#define shmem_rmdir shmem_unlink - /* * The VFS layer already does all the dentry stuff for rename, * we just have to decrement the usage count for the target if @@ -567,27 +910,77 @@ if (shmem_empty(new_dentry)) { struct inode *inode = new_dentry->d_inode; if (inode) { + inode->i_ctime = CURRENT_TIME; inode->i_nlink--; dput(new_dentry); } error = 0; + old_dentry->d_inode->i_ctime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; } return error; } -static int shmem_mmap(struct file * file, struct vm_area_struct * vma) +static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname) { - struct vm_operations_struct * ops; - struct inode *inode = file->f_dentry->d_inode; + int error; + int len; + struct inode *inode; + struct page *page; + char *kaddr; - ops = &shmem_private_vm_ops; - if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) - ops = &shmem_shared_vm_ops; - if (!inode->i_sb || !S_ISREG(inode->i_mode)) - return -EACCES; - UPDATE_ATIME(inode); - vma->vm_ops = ops; + error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0); + if (error) + return error; + + len = strlen(symname); + if (len > PAGE_SIZE) + return -ENAMETOOLONG; + + inode = dentry->d_inode; + down(&inode->i_sem); + page = shmem_getpage_locked(inode, 0); + if (IS_ERR(page)) + goto fail; + kaddr = kmap(page); + memcpy(kaddr, symname, len); + kunmap(page); + inode->i_size = len; + SetPageDirty(page); + UnlockPage(page); + page_cache_release(page); + up(&inode->i_sem); + dir->i_ctime = dir->i_mtime = CURRENT_TIME; return 0; +fail: + up(&inode->i_sem); + return PTR_ERR(page); +} + +static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct page * page; + int res = shmem_getpage(dentry->d_inode, 0, &page); + + if (res) + return res; + + res = vfs_readlink(dentry,buffer,buflen, kmap(page)); + kunmap(page); + page_cache_release(page); + return res; +} + +static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct page * page; + int res = shmem_getpage(dentry->d_inode, 0, &page); + if (res) + return res; + + res = vfs_follow_link(nd, kmap(page)); + kunmap(page); + page_cache_release(page); + return res; } static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes) @@ -600,16 +993,24 @@ for ( ; this_char; this_char = strtok(NULL,",")) { if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; - if (!strcmp(this_char,"nr_blocks")) { + if (!strcmp(this_char,"size")) { + unsigned long long size; if (!value || !*value || !blocks) return 1; - *blocks = simple_strtoul(value,&value,0); + size = memparse(value,&value); + if (*value) + return 1; + *blocks = size >> PAGE_CACHE_SHIFT; + } else if (!strcmp(this_char,"nr_blocks")) { + if (!value || !*value || !blocks) + return 1; + *blocks = memparse(value,&value); if (*value) return 1; } else if (!strcmp(this_char,"nr_inodes")) { if (!value || !*value || !inodes) return 1; - *inodes = simple_strtoul(value,&value,0); + *inodes = memparse(value,&value); if (*value) return 1; } else if (!strcmp(this_char,"mode")) { @@ -622,9 +1023,42 @@ else return 1; } + return 0; +} + +static int shmem_remount_fs (struct super_block *sb, int *flags, char *data) +{ + int error; + unsigned long max_blocks, blocks; + unsigned long max_inodes, inodes; + struct shmem_sb_info *info = &sb->u.shmem_sb; + + if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) + return -EINVAL; + + spin_lock(&info->stat_lock); + blocks = info->max_blocks - info->free_blocks; + inodes = info->max_inodes - info->free_inodes; + error = -EINVAL; + if (max_blocks < blocks) + goto out; + if (max_inodes < inodes) + goto out; + error = 0; + info->max_blocks = max_blocks; + info->free_blocks = max_blocks - blocks; + info->max_inodes = max_inodes; + info->free_inodes = max_inodes - inodes; +out: + spin_unlock(&info->stat_lock); + return error; +} +int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ return 0; } +#endif static struct super_block *shmem_read_super(struct super_block * sb, void * data, int silent) { @@ -634,19 +1068,22 @@ unsigned long inodes = ULONG_MAX; /* unlimited */ int mode = S_IRWXUGO | S_ISVTX; +#ifdef CONFIG_TMPFS if (shmem_parse_options (data, &mode, &blocks, &inodes)) { - printk(KERN_ERR "shmem fs invalid option\n"); + printk(KERN_ERR "tmpfs invalid option\n"); return NULL; } +#endif spin_lock_init (&sb->u.shmem_sb.stat_lock); sb->u.shmem_sb.max_blocks = blocks; sb->u.shmem_sb.free_blocks = blocks; sb->u.shmem_sb.max_inodes = inodes; sb->u.shmem_sb.free_inodes = inodes; + sb->s_maxbytes = (unsigned long long)(SHMEM_NR_DIRECT + (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)) << PAGE_CACHE_SHIFT; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = SHMEM_MAGIC; + sb->s_magic = TMPFS_MAGIC; sb->s_op = &shmem_ops; inode = shmem_get_inode(sb, S_IFDIR | mode, 0); if (!inode) @@ -661,103 +1098,108 @@ return sb; } -static int shmem_remount_fs (struct super_block *sb, int *flags, char *data) -{ - int error; - unsigned long max_blocks, blocks; - unsigned long max_inodes, inodes; - struct shmem_sb_info *info = &sb->u.shmem_sb; - if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) - return -EINVAL; - - spin_lock(&info->stat_lock); - blocks = info->max_blocks - info->free_blocks; - inodes = info->max_inodes - info->free_inodes; - error = -EINVAL; - if (max_blocks < blocks) - goto out; - if (max_inodes < inodes) - goto out; - error = 0; - info->max_blocks = max_blocks; - info->free_blocks = max_blocks - blocks; - info->max_inodes = max_inodes; - info->free_inodes = max_inodes - inodes; -out: - spin_unlock(&info->stat_lock); - return error; -} static struct address_space_operations shmem_aops = { writepage: shmem_writepage }; static struct file_operations shmem_file_operations = { - mmap: shmem_mmap + mmap: shmem_mmap, +#ifdef CONFIG_TMPFS + read: shmem_file_read, + write: shmem_file_write, + fsync: shmem_sync_file, +#endif }; static struct inode_operations shmem_inode_operations = { truncate: shmem_truncate, }; +static struct inode_operations shmem_symlink_inode_operations = { + truncate: shmem_truncate, +#ifdef CONFIG_TMPFS + readlink: shmem_readlink, + follow_link: shmem_follow_link, +#endif +}; + static struct file_operations shmem_dir_operations = { read: generic_read_dir, readdir: dcache_readdir, +#ifdef CONFIG_TMPFS + fsync: shmem_sync_file, +#endif }; static struct inode_operations shmem_dir_inode_operations = { +#ifdef CONFIG_TMPFS create: shmem_create, lookup: shmem_lookup, link: shmem_link, unlink: shmem_unlink, + symlink: shmem_symlink, mkdir: shmem_mkdir, rmdir: shmem_rmdir, mknod: shmem_mknod, rename: shmem_rename, +#endif }; static struct super_operations shmem_ops = { +#ifdef CONFIG_TMPFS statfs: shmem_statfs, remount_fs: shmem_remount_fs, +#endif delete_inode: shmem_delete_inode, put_inode: force_delete, }; -static struct vm_operations_struct shmem_private_vm_ops = { - nopage: shmem_nopage, -}; - -static struct vm_operations_struct shmem_shared_vm_ops = { +static struct vm_operations_struct shmem_vm_ops = { nopage: shmem_nopage, }; +#ifdef CONFIG_TMPFS +/* type "shm" will be tagged obsolete in 2.5 */ static DECLARE_FSTYPE(shmem_fs_type, "shm", shmem_read_super, FS_LITTER); +static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER); +#else +static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER|FS_NOMOUNT); +#endif static int __init init_shmem_fs(void) { int error; struct vfsmount * res; + if ((error = register_filesystem(&tmpfs_fs_type))) { + printk (KERN_ERR "Could not register tmpfs\n"); + return error; + } +#ifdef CONFIG_TMPFS if ((error = register_filesystem(&shmem_fs_type))) { - printk (KERN_ERR "Could not register shmem fs\n"); + printk (KERN_ERR "Could not register shm fs\n"); return error; } - - res = kern_mount(&shmem_fs_type); + devfs_mk_dir (NULL, "shm", NULL); +#endif + res = kern_mount(&tmpfs_fs_type); if (IS_ERR (res)) { - printk (KERN_ERR "could not kern_mount shmem fs\n"); - unregister_filesystem(&shmem_fs_type); + printk (KERN_ERR "could not kern_mount tmpfs\n"); + unregister_filesystem(&tmpfs_fs_type); return PTR_ERR(res); } - devfs_mk_dir (NULL, "shm", NULL); return 0; } static void __exit exit_shmem_fs(void) { +#ifdef CONFIG_TMPFS unregister_filesystem(&shmem_fs_type); +#endif + unregister_filesystem(&tmpfs_fs_type); } module_init(init_shmem_fs) @@ -853,7 +1295,7 @@ this.name = name; this.len = strlen(name); this.hash = 0; /* will go */ - root = shmem_fs_type.kern_mnt->mnt_root; + root = tmpfs_fs_type.kern_mnt->mnt_root; dentry = d_alloc(root, &this); if (!dentry) goto out; @@ -870,7 +1312,8 @@ d_instantiate(dentry, inode); dentry->d_inode->i_size = size; - file->f_vfsmnt = mntget(shmem_fs_type.kern_mnt); + shmem_truncate(inode); + file->f_vfsmnt = mntget(tmpfs_fs_type.kern_mnt); file->f_dentry = dentry; file->f_op = &shmem_file_operations; file->f_mode = FMODE_WRITE | FMODE_READ; @@ -901,6 +1344,8 @@ if (vma->vm_file) fput (vma->vm_file); vma->vm_file = file; - vma->vm_ops = &shmem_shared_vm_ops; + vma->vm_ops = &shmem_vm_ops; return 0; } + +EXPORT_SYMBOL(shmem_file_setup); diff -u --recursive --new-file v2.4.3/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.4.3/linux/mm/swap_state.c Fri Dec 29 15:04:27 2000 +++ linux/mm/swap_state.c Fri Apr 6 16:35:06 2001 @@ -17,8 +17,23 @@ #include <asm/pgtable.h> +/* + * We may have stale swap cache pages in memory: notice + * them here and get rid of the unnecessary final write. + */ static int swap_writepage(struct page *page) { + /* One for the page cache, one for this user, one for page->buffers */ + if (page_count(page) > 2 + !!page->buffers) + goto in_use; + if (swap_count(page) > 1) + goto in_use; + + /* We could remove it here, but page_launder will do it anyway */ + UnlockPage(page); + return 0; + +in_use: rw_swap_page(WRITE, page, 0); return 0; } @@ -129,26 +144,6 @@ delete_from_swap_cache_nolock(page); UnlockPage(page); } - -/* - * Perform a free_page(), also freeing any swap cache associated with - * this page if it is the last user of the page. Can not do a lock_page, - * as we are holding the page_table_lock spinlock. - */ -void free_page_and_swap_cache(struct page *page) -{ - /* - * If we are the only user, then try to free up the swap cache. - */ - if (PageSwapCache(page) && !TryLockPage(page)) { - if (!is_page_shared(page)) { - delete_from_swap_cache_nolock(page); - } - UnlockPage(page); - } - page_cache_release(page); -} - /* * Lookup a swap entry in the swap cache. A found page will be returned diff -u --recursive --new-file v2.4.3/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.3/linux/mm/vmscan.c Thu Mar 22 11:00:51 2001 +++ linux/mm/vmscan.c Thu Apr 12 12:10:25 2001 @@ -563,7 +563,7 @@ /* * Unlock the page and drop the extra reference. - * We can only do it here because we ar accessing + * We can only do it here because we are accessing * the page struct above. */ UnlockPage(page); @@ -912,7 +912,7 @@ * Kswapd main loop. */ for (;;) { - static int recalc = 0; + static long recalc = 0; /* If needed, try to free some memory. */ if (inactive_shortage() || free_shortage()) diff -u --recursive --new-file v2.4.3/linux/net/802/TODO linux/net/802/TODO --- v2.4.3/linux/net/802/TODO Thu Dec 12 06:54:22 1996 +++ linux/net/802/TODO Fri Apr 6 10:51:19 2001 @@ -9,7 +9,7 @@ 2. The code is currently able to handle one connection only, there is more work in register_cl2llc_client() to make a chain of llc structures and in mac_data_indicate() to find back -the llc structure addressed by an incomming frame. +the llc structure addressed by an incoming frame. According to IEEE, connections are identified by (remote mac + local mac + dsap + ssap). dsap and ssap do not seem important: existing applications always use the same dsap/ssap. Its probably sufficient to index on diff -u --recursive --new-file v2.4.3/linux/net/802/cl2llc.c linux/net/802/cl2llc.c --- v2.4.3/linux/net/802/cl2llc.c Fri Feb 9 11:34:13 2001 +++ linux/net/802/cl2llc.c Fri Apr 6 10:51:19 2001 @@ -162,7 +162,7 @@ * Interpret_pseudo_code() executes the actions in the connection component * state transition table. Table 4 in document on p88. * - * If this function is called to handle an incomming pdu, skb will point + * If this function is called to handle an incoming pdu, skb will point * to the buffer with the pdu and type will contain the decoded pdu type. * * If called by data_request skb points to an skb that was skb_alloc-ed by diff -u --recursive --new-file v2.4.3/linux/net/802/cl2llc.pre linux/net/802/cl2llc.pre --- v2.4.3/linux/net/802/cl2llc.pre Sat Nov 29 10:41:10 1997 +++ linux/net/802/cl2llc.pre Fri Apr 6 10:51:19 2001 @@ -162,7 +162,7 @@ * Interpret_pseudo_code() executes the actions in the connection component * state transition table. Table 4 in document on p88. * - * If this function is called to handle an incomming pdu, skb will point + * If this function is called to handle an incoming pdu, skb will point * to the buffer with the pdu and type will contain the decoded pdu type. * * If called by data_request skb points to an skb that was skb_alloc-ed by diff -u --recursive --new-file v2.4.3/linux/net/802/llc_sendpdu.c linux/net/802/llc_sendpdu.c --- v2.4.3/linux/net/802/llc_sendpdu.c Fri Feb 9 11:29:44 2001 +++ linux/net/802/llc_sendpdu.c Fri Apr 6 10:51:19 2001 @@ -98,7 +98,7 @@ /* * Sendpdu() constructs an output frame in a new skb and - * gives it to the MAC layer for transmision. + * gives it to the MAC layer for transmission. * This function is not used to send I pdus. * No queues are updated here, nothing is saved for retransmission. * @@ -186,7 +186,7 @@ /* * llc_sendipdu() Completes an I pdu in an existing skb and gives it - * to the MAC layer for transmision. + * to the MAC layer for transmission. * Parameter "type" must be either I_CMD or I_RSP. * The skb is not freed after xmit, it is kept in case a retransmission * is requested. If needed it can be picked up again from the rtq. diff -u --recursive --new-file v2.4.3/linux/net/802/pseudo/pseudocode linux/net/802/pseudo/pseudocode --- v2.4.3/linux/net/802/pseudo/pseudocode Thu Dec 12 06:54:22 1996 +++ linux/net/802/pseudo/pseudocode Fri Apr 6 10:51:19 2001 @@ -246,7 +246,7 @@ START_REJ_TIMER ; ; the order of opcodes in NORMAL8 is changed. -; the transition table will execute NORMAL8A for incomming pdus +; the transition table will execute NORMAL8A for incoming pdus ; with p/f 1, pdus with pf 0 are treated in NORMAL8B. ; NORMAL8A V(R):=V(R)+1 diff -u --recursive --new-file v2.4.3/linux/net/802/transit/pdutr.pre linux/net/802/transit/pdutr.pre --- v2.4.3/linux/net/802/transit/pdutr.pre Thu Dec 12 06:54:22 1996 +++ linux/net/802/transit/pdutr.pre Fri Apr 6 10:51:19 2001 @@ -1,6 +1,6 @@ COMPILE pdutr INDEX ; -; Transition tables for incomming pdu events. +; Transition tables for incoming pdu events. ; translate this thing into C with ; awk -f ./compile.awk pdu.trans > pdutr.h ; diff -u --recursive --new-file v2.4.3/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.4.3/linux/net/appletalk/ddp.c Mon Jan 22 13:32:10 2001 +++ linux/net/appletalk/ddp.c Thu Apr 12 12:11:39 2001 @@ -1672,7 +1672,7 @@ sk, size, dev->name); size += dev->hard_header_len; - skb = sock_alloc_send_skb(sk, size, 0, (flags & MSG_DONTWAIT), &err); + skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err); if (!skb) return err; @@ -1913,6 +1913,7 @@ sendmsg: atalk_sendmsg, recvmsg: atalk_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> @@ -1988,7 +1989,7 @@ * Use counts are incremented/decremented when * sockets are created/deleted. * - * AppleTalk interfaces are not incremented untill atalkd is run + * AppleTalk interfaces are not incremented until atalkd is run * and are only decremented when they are downed. * * Ergo, before the AppleTalk module can be removed, all AppleTalk diff -u --recursive --new-file v2.4.3/linux/net/atm/addr.c linux/net/atm/addr.c --- v2.4.3/linux/net/atm/addr.c Fri Dec 29 14:35:47 2000 +++ linux/net/atm/addr.c Fri Apr 6 10:51:19 2001 @@ -52,25 +52,26 @@ sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL); } +/* + * This is called from atm_ioctl only. You must hold the lock as a caller + */ -void reset_addr(struct atm_dev *dev) +void atm_reset_addr(struct atm_dev *dev) { struct atm_dev_addr *this; down(&local_lock); - spin_lock (&atm_dev_lock); while (dev->local) { this = dev->local; dev->local = this->next; kfree(this); } up(&local_lock); - spin_unlock (&atm_dev_lock); notify_sigd(dev); } -int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) { struct atm_dev_addr **walk; int error; @@ -96,7 +97,7 @@ } -int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) { struct atm_dev_addr **walk,*this; int error; @@ -119,7 +120,7 @@ } -int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) +int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) { struct atm_dev_addr *walk; int total; diff -u --recursive --new-file v2.4.3/linux/net/atm/addr.h linux/net/atm/addr.h --- v2.4.3/linux/net/atm/addr.h Mon Dec 11 13:33:43 2000 +++ linux/net/atm/addr.h Fri Apr 6 10:51:19 2001 @@ -10,9 +10,9 @@ #include <linux/atmdev.h> -void reset_addr(struct atm_dev *dev); -int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); +void atm_reset_addr(struct atm_dev *dev); +int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); +int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); +int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); #endif diff -u --recursive --new-file v2.4.3/linux/net/atm/common.c linux/net/atm/common.c --- v2.4.3/linux/net/atm/common.c Fri Feb 9 11:34:13 2001 +++ linux/net/atm/common.c Fri Apr 6 10:51:19 2001 @@ -867,7 +867,7 @@ ret_val = -EPERM; goto done; } - reset_addr(dev); + atm_reset_addr(dev); break; case ATM_ADDADDR: case ATM_DELADDR: @@ -883,13 +883,13 @@ goto done; } if (cmd == ATM_ADDADDR) - ret_val = add_addr(dev,&addr); + ret_val = atm_add_addr(dev,&addr); else - ret_val = del_addr(dev,&addr); + ret_val = atm_del_addr(dev,&addr); goto done; } case ATM_GETADDR: - size = get_addr(dev,buf,len); + size = atm_get_addr(dev,buf,len); if (size < 0) ret_val = size; else diff -u --recursive --new-file v2.4.3/linux/net/atm/pvc.c linux/net/atm/pvc.c --- v2.4.3/linux/net/atm/pvc.c Sat Nov 11 18:53:33 2000 +++ linux/net/atm/pvc.c Thu Apr 12 12:11:39 2001 @@ -95,6 +95,7 @@ sendmsg: atm_sendmsg, recvmsg: atm_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; diff -u --recursive --new-file v2.4.3/linux/net/atm/svc.c linux/net/atm/svc.c --- v2.4.3/linux/net/atm/svc.c Wed Nov 15 00:41:03 2000 +++ linux/net/atm/svc.c Thu Apr 12 12:11:39 2001 @@ -408,6 +408,7 @@ sendmsg: atm_sendmsg, recvmsg: atm_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; diff -u --recursive --new-file v2.4.3/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.4.3/linux/net/ax25/af_ax25.c Fri Feb 9 11:34:13 2001 +++ linux/net/ax25/af_ax25.c Thu Apr 12 12:11:39 2001 @@ -1451,7 +1451,7 @@ /* Assume the worst case */ size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, size - len); @@ -1805,6 +1805,7 @@ sendmsg: ax25_sendmsg, recvmsg: ax25_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --recursive --new-file v2.4.3/linux/net/core/datagram.c linux/net/core/datagram.c --- v2.4.3/linux/net/core/datagram.c Sat Feb 3 10:39:12 2001 +++ linux/net/core/datagram.c Thu Apr 12 12:11:39 2001 @@ -36,6 +36,7 @@ #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/poll.h> +#include <linux/highmem.h> #include <net/ip.h> #include <net/protocol.h> @@ -192,26 +193,216 @@ * Copy a datagram to a linear buffer. */ -int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) +int skb_copy_datagram(const struct sk_buff *skb, int offset, char *to, int size) { - int err = -EFAULT; + struct iovec iov = { to, size }; - if (!copy_to_user(to, skb->h.raw + offset, size)) - err = 0; - return err; + return skb_copy_datagram_iovec(skb, offset, &iov, size); } - /* * Copy a datagram to an iovec. * Note: the iovec is modified during the copy. */ - -int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, - int size) +int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec *to, + int len) +{ + int i, copy; + int start = skb->len - skb->data_len; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + if (memcpy_toiovec(to, skb->data + offset, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + } + + /* Copy paged appendix. Hmm... why does this look so complicated? */ + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + int err; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + vaddr = kmap(page); + err = memcpy_toiovec(to, vaddr + frag->page_offset + + offset-start, copy); + kunmap(page); + if (err) + goto fault; + if (!(len -= copy)) + return 0; + offset += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_iovec(list, offset-start, to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + } + start = end; + } + } + if (len == 0) + return 0; + +fault: + return -EFAULT; +} + +int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump) +{ + int i, copy; + int start = skb->len - skb->data_len; + int pos = 0; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + int err = 0; + if (copy > len) + copy = len; + *csump = csum_and_copy_to_user(skb->data+offset, to, copy, *csump, &err); + if (err) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + pos = copy; + } + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + unsigned int csum2; + int err = 0; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + vaddr = kmap(page); + csum2 = csum_and_copy_to_user(vaddr + frag->page_offset + + offset-start, to, copy, 0, &err); + kunmap(page); + if (err) + goto fault; + *csump = csum_block_add(*csump, csum2, pos); + if (!(len -= copy)) + return 0; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + unsigned int csum2 = 0; + if (copy > len) + copy = len; + if (skb_copy_and_csum_datagram(list, offset-start, to, copy, &csum2)) + goto fault; + *csump = csum_block_add(*csump, csum2, pos); + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + } + if (len == 0) + return 0; + +fault: + return -EFAULT; +} + +/* Copy and checkum skb to user iovec. Caller _must_ check that + skb will fit to this iovec. + + Returns: 0 - success. + -EINVAL - checksum failure. + -EFAULT - fault during copy. Beware, in this case iovec can be + modified! + */ + +int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct iovec *iov) { - return memcpy_toiovec(to, skb->h.raw + offset, size); + unsigned int csum; + int chunk = skb->len - hlen; + + /* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */ + while (iov->iov_len == 0) + iov++; + + if (iov->iov_len < chunk) { + if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk+hlen, skb->csum))) + goto csum_error; + if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) + goto fault; + } else { + csum = csum_partial(skb->data, hlen, skb->csum); + if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base, chunk, &csum)) + goto fault; + if ((unsigned short)csum_fold(csum)) + goto csum_error; + iov->iov_len -= chunk; + iov->iov_base += chunk; + } + return 0; + +csum_error: + return -EINVAL; + +fault: + return -EFAULT; } + + /* * Datagram poll: Again totally generic. This also handles diff -u --recursive --new-file v2.4.3/linux/net/core/dev.c linux/net/core/dev.c --- v2.4.3/linux/net/core/dev.c Fri Mar 2 11:02:15 2001 +++ linux/net/core/dev.c Thu Apr 12 12:11:39 2001 @@ -91,6 +91,8 @@ #include <net/dst.h> #include <net/pkt_sched.h> #include <net/profile.h> +#include <net/checksum.h> +#include <linux/highmem.h> #include <linux/init.h> #include <linux/kmod.h> #include <linux/module.h> @@ -503,7 +505,7 @@ } /** - * dev_getbyhwaddr - find a device by its hardware addres + * dev_getbyhwaddr - find a device by its hardware address * @type: media type of device * @ha: hardware address * @@ -871,12 +873,10 @@ */ skb2->mac.raw = skb2->data; - if (skb2->nh.raw < skb2->data || skb2->nh.raw >= skb2->tail) { + if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) { if (net_ratelimit()) printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name); skb2->nh.raw = skb2->data; - if (dev->hard_header) - skb2->nh.raw += dev->hard_header_len; } skb2->h.raw = skb2->nh.raw; @@ -887,6 +887,55 @@ br_read_unlock(BR_NETPROTO_LOCK); } +/* Calculate csum in the case, when packet is misrouted. + * If it failed by some reason, ignore and send skb with wrong + * checksum. + */ +struct sk_buff * skb_checksum_help(struct sk_buff *skb) +{ + int offset; + unsigned int csum; + + offset = skb->h.raw - skb->data; + if (offset > (int)skb->len) + BUG(); + csum = skb_checksum(skb, offset, skb->len-offset, 0); + + offset = skb->tail - skb->h.raw; + if (offset <= 0) + BUG(); + if (skb->csum+2 > offset) + BUG(); + + *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; + return skb; +} + +#ifdef CONFIG_HIGHMEM +/* Actually, we should eliminate this check as soon as we know, that: + * 1. IOMMU is present and allows to map all the memory. + * 2. No high memory really exists on this machine. + */ + +static inline int +illegal_highdma(struct net_device *dev, struct sk_buff *skb) +{ + int i; + + if (dev->features&NETIF_F_HIGHDMA) + return 0; + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) + if (skb_shinfo(skb)->frags[i].page >= highmem_start_page) + return 1; + + return 0; +} +#else +#define illegal_highdma(dev, skb) (0) +#endif + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -899,12 +948,41 @@ * guarantee the frame will be transmitted as it may be dropped due * to congestion or traffic shaping. */ - + int dev_queue_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct Qdisc *q; + if (skb_shinfo(skb)->frag_list && + !(dev->features&NETIF_F_FRAGLIST) && + skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + + /* Fragmented skb is linearized if device does not support SG, + * or if at least one of fragments is in highmem and device + * does not support DMA from it. + */ + if (skb_shinfo(skb)->nr_frags && + (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) && + skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + + /* If packet is not checksummed and device does not support + * checksumming for this protocol, complete checksumming here. + */ + if (skb->ip_summed == CHECKSUM_HW && + (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) && + (!(dev->features&NETIF_F_IP_CSUM) || + skb->protocol != htons(ETH_P_IP)))) { + if ((skb = skb_checksum_help(skb)) == NULL) + return -ENOMEM; + } + /* Grab device queue */ spin_lock_bh(&dev->queue_lock); q = dev->qdisc; @@ -1182,6 +1260,10 @@ skb = skb_clone(skb, GFP_ATOMIC); if (skb == NULL) return ret; + } + if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return ret; } /* The assumption (correct one) is that old protocols diff -u --recursive --new-file v2.4.3/linux/net/core/filter.c linux/net/core/filter.c --- v2.4.3/linux/net/core/filter.c Sun Apr 2 15:38:54 2000 +++ linux/net/core/filter.c Thu Apr 12 12:11:39 2001 @@ -72,7 +72,7 @@ /* len is UNSIGNED. Byte wide insns relies only on implicit type casts to prevent reading arbitrary memory locations. */ - unsigned int len = skb->len; + unsigned int len = skb->len-skb->data_len; struct sock_filter *fentry; /* We walk down these */ u32 A = 0; /* Accumulator */ u32 X = 0; /* Index Register */ @@ -201,7 +201,7 @@ case BPF_LD|BPF_W|BPF_ABS: k = fentry->k; load_w: - if(k+sizeof(u32) <= len) { + if(k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) { A = ntohl(*(u32*)&data[k]); continue; } @@ -214,13 +214,19 @@ A = ntohl(*(u32*)ptr); continue; } + } else { + u32 tmp; + if (!skb_copy_bits(skb, k, &tmp, 4)) { + A = ntohl(tmp); + continue; + } } return 0; case BPF_LD|BPF_H|BPF_ABS: k = fentry->k; load_h: - if(k + sizeof(u16) <= len) { + if(k >= 0 && (unsigned int) (k + sizeof(u16)) <= len) { A = ntohs(*(u16*)&data[k]); continue; } @@ -233,13 +239,19 @@ A = ntohs(*(u16*)ptr); continue; } + } else { + u16 tmp; + if (!skb_copy_bits(skb, k, &tmp, 2)) { + A = ntohs(tmp); + continue; + } } return 0; case BPF_LD|BPF_B|BPF_ABS: k = fentry->k; load_b: - if(k < len) { + if(k >= 0 && (unsigned int)k < len) { A = data[k]; continue; } @@ -252,6 +264,12 @@ A = *ptr; continue; } + } else { + u8 tmp; + if (!skb_copy_bits(skb, k, &tmp, 1)) { + A = tmp; + continue; + } } return 0; @@ -277,7 +295,7 @@ case BPF_LDX|BPF_B|BPF_MSH: k = fentry->k; - if(k >= len) + if(k >= 0 && (unsigned int)k >= len) return (0); X = (data[k] & 0xf) << 2; continue; diff -u --recursive --new-file v2.4.3/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.4.3/linux/net/core/iovec.c Fri Feb 9 11:29:44 2001 +++ linux/net/core/iovec.c Thu Apr 12 12:11:39 2001 @@ -102,48 +102,6 @@ return err; } -/* Copy and checkum skb to user iovec. Caller _must_ check that - skb will fit to this iovec. - - Returns: 0 - success. - -EINVAL - checksum failure. - -EFAULT - fault during copy. Beware, in this case iovec can be - modified! - */ - -int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen) -{ - unsigned int csum; - int chunk = skb->len - hlen; - - /* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */ - while (iov->iov_len == 0) - iov++; - - if (iov->iov_len < chunk) { - if ((unsigned short)csum_fold(csum_partial(skb->h.raw, chunk+hlen, skb->csum))) - goto csum_error; - if (memcpy_toiovec(iov, skb->h.raw + hlen, chunk)) - goto fault; - } else { - int err = 0; - csum = csum_partial(skb->h.raw, hlen, skb->csum); - csum = csum_and_copy_to_user(skb->h.raw+hlen, iov->iov_base, - chunk, csum, &err); - if (err || ((unsigned short)csum_fold(csum))) - goto csum_error; - iov->iov_len -= chunk; - iov->iov_base += chunk; - } - return 0; - -csum_error: - return -EINVAL; - -fault: - return -EFAULT; -} - /* * In kernel copy to iovec. Returns -EFAULT on error. * diff -u --recursive --new-file v2.4.3/linux/net/core/netfilter.c linux/net/core/netfilter.c --- v2.4.3/linux/net/core/netfilter.c Mon Jan 22 13:30:21 2001 +++ linux/net/core/netfilter.c Thu Apr 12 12:11:39 2001 @@ -451,6 +451,19 @@ unsigned int verdict; int ret = 0; + /* This stopgap cannot be removed until all the hooks are audited. */ + if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + if (skb->ip_summed == CHECKSUM_HW) { + if (outdev == NULL) { + skb->ip_summed = CHECKSUM_NONE; + } else { + skb_checksum_help(skb); + } + } + /* We may already have this, but read-locks nest anyway */ br_read_lock_bh(BR_NETPROTO_LOCK); diff -u --recursive --new-file v2.4.3/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.4.3/linux/net/core/skbuff.c Fri Feb 16 16:06:17 2001 +++ linux/net/core/skbuff.c Thu Apr 12 12:11:39 2001 @@ -4,7 +4,7 @@ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk> * Florian La Roche <rzsfl@rz.uni-sb.de> * - * Version: $Id: skbuff.c,v 1.75 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: skbuff.c,v 1.87 2001/03/06 22:09:50 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -50,6 +50,7 @@ #include <linux/skbuff.h> #include <linux/cache.h> #include <linux/init.h> +#include <linux/highmem.h> #include <net/ip.h> #include <net/protocol.h> @@ -185,8 +186,8 @@ } /* Get the DATA. Size must match skb_add_mtu(). */ - size = ((size + 15) & ~15); - data = kmalloc(size + sizeof(atomic_t), gfp_mask); + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); if (data == NULL) goto nodata; @@ -202,9 +203,12 @@ /* Set up other state */ skb->len = 0; skb->cloned = 0; + skb->data_len = 0; atomic_set(&skb->users, 1); - atomic_set(skb_datarefp(skb), 1); + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; return skb; nodata: @@ -248,14 +252,50 @@ #endif } +static void skb_drop_fraglist(struct sk_buff *skb) +{ + struct sk_buff *list = skb_shinfo(skb)->frag_list; + + skb_shinfo(skb)->frag_list = NULL; + + do { + struct sk_buff *this = list; + list = list->next; + kfree_skb(this); + } while (list); +} + +static void skb_clone_fraglist(struct sk_buff *skb) +{ + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) + skb_get(list); +} + +static void skb_release_data(struct sk_buff *skb) +{ + if (!skb->cloned || + atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) { + if (skb_shinfo(skb)->nr_frags) { + int i; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + put_page(skb_shinfo(skb)->frags[i].page); + } + + if (skb_shinfo(skb)->frag_list) + skb_drop_fraglist(skb); + + kfree(skb->head); + } +} + /* * Free an skbuff by memory without cleaning the state. */ void kfree_skbmem(struct sk_buff *skb) { - if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb))) - kfree(skb->head); - + skb_release_data(skb); skb_head_to_pool(skb); } @@ -316,18 +356,53 @@ return NULL; } - memcpy(n, skb, sizeof(*n)); - atomic_inc(skb_datarefp(skb)); - skb->cloned = 1; - - dst_clone(n->dst); - n->cloned = 1; +#define C(x) n->x = skb->x + n->next = n->prev = NULL; n->list = NULL; n->sk = NULL; + C(stamp); + C(dev); + C(h); + C(nh); + C(mac); + C(dst); + dst_clone(n->dst); + memcpy(n->cb, skb->cb, sizeof(skb->cb)); + C(len); + C(data_len); + C(csum); + n->cloned = 1; + C(pkt_type); + C(ip_summed); + C(priority); atomic_set(&n->users, 1); + C(protocol); + C(security); + C(truesize); + C(head); + C(data); + C(tail); + C(end); n->destructor = NULL; #ifdef CONFIG_NETFILTER + C(nfmark); + C(nfcache); + C(nfct); +#ifdef CONFIG_NETFILTER_DEBUG + C(nf_debug); +#endif +#endif /*CONFIG_NETFILTER*/ +#if defined(CONFIG_HIPPI) + C(private); +#endif +#ifdef CONFIG_NET_SCHED + C(tc_index); +#endif + + atomic_inc(&(skb_shinfo(skb)->dataref)); + skb->cloned = 1; +#ifdef CONFIG_NETFILTER nf_conntrack_get(skb->nfct); #endif return n; @@ -350,7 +425,6 @@ new->nh.raw=old->nh.raw+offset; new->mac.raw=old->mac.raw+offset; memcpy(new->cb, old->cb, sizeof(old->cb)); - new->used=old->used; atomic_set(&new->users, 1); new->pkt_type=old->pkt_type; new->stamp=old->stamp; @@ -371,7 +445,7 @@ } /** - * skb_copy - copy an sk_buff + * skb_copy - create private copy of an sk_buff * @skb: buffer to copy * @gfp_mask: allocation priority * @@ -380,18 +454,115 @@ * data to alter. Returns %NULL on failure or the pointer to the buffer * on success. The returned buffer has a reference count of 1. * - * You must pass %GFP_ATOMIC as the allocation priority if this function - * is called from an interrupt. + * As by-product this function converts non-linear &sk_buff to linear + * one, so that &sk_buff becomes completely private and caller is allowed + * to modify all the data of returned buffer. This means that this + * function is not recommended for use in circumstances when only + * header is going to be modified. Use pskb_copy() instead. */ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask) { struct sk_buff *n; + int headerlen = skb->data-skb->head; + + /* + * Allocate the copy buffer + */ + n=alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask); + if(n==NULL) + return NULL; + + /* Set the data pointer */ + skb_reserve(n,headerlen); + /* Set the tail pointer and length */ + skb_put(n,skb->len); + n->csum = skb->csum; + n->ip_summed = skb->ip_summed; + + if (skb_copy_bits(skb, -headerlen, n->head, headerlen+skb->len)) + BUG(); + + copy_skb_header(n, skb); + + return n; +} + +/* Keep head the same: replace data */ +int skb_linearize(struct sk_buff *skb, int gfp_mask) +{ + unsigned int size; + u8 *data; + long offset; + int headerlen = skb->data - skb->head; + int expand = (skb->tail+skb->data_len) - skb->end; + + if (skb_shared(skb)) + BUG(); + + if (expand <= 0) + expand = 0; + + size = (skb->end - skb->head + expand); + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (data == NULL) + return -ENOMEM; + + /* Copy entire thing */ + if (skb_copy_bits(skb, -headerlen, data, headerlen+skb->len)) + BUG(); + + /* Offset between the two in bytes */ + offset = data - skb->head; + + /* Free old data. */ + skb_release_data(skb); + + skb->head = data; + skb->end = data + size; + + /* Set up new pointers */ + skb->h.raw += offset; + skb->nh.raw += offset; + skb->mac.raw += offset; + skb->tail += offset; + skb->data += offset; + + /* Set up shinfo */ + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; + + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; + + skb->tail += skb->data_len; + skb->data_len = 0; + return 0; +} + + +/** + * pskb_copy - create copy of an sk_buff with private head. + * @skb: buffer to copy + * @gfp_mask: allocation priority + * + * Make a copy of both an &sk_buff and part of its data, located + * in header. Fragmented data remain shared. This is used when + * the caller wishes to modify only header of &sk_buff and needs + * private copy of the header to alter. Returns %NULL on failure + * or the pointer to the buffer on success. + * The returned buffer has a reference count of 1. + */ + +struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask) +{ + struct sk_buff *n; /* * Allocate the copy buffer */ - n=alloc_skb(skb->end - skb->head, gfp_mask); if(n==NULL) return NULL; @@ -399,16 +570,120 @@ /* Set the data pointer */ skb_reserve(n,skb->data-skb->head); /* Set the tail pointer and length */ - skb_put(n,skb->len); + skb_put(n,skb_headlen(skb)); /* Copy the bytes */ - memcpy(n->head,skb->head,skb->end-skb->head); + memcpy(n->data, skb->data, n->len); n->csum = skb->csum; + n->ip_summed = skb->ip_summed; + + n->data_len = skb->data_len; + n->len = skb->len; + + if (skb_shinfo(skb)->nr_frags) { + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; + get_page(skb_shinfo(n)->frags[i].page); + } + skb_shinfo(n)->nr_frags = i; + } + + if (skb_shinfo(skb)->frag_list) { + skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; + skb_clone_fraglist(n); + } + copy_skb_header(n, skb); return n; } /** + * pskb_expand_head - reallocate header of &sk_buff + * @skb: buffer to reallocate + * @nhead: room to add at head + * @ntail: room to add at tail + * @gfp_mask: allocation priority + * + * Expands (or creates identical copy, if &nhead and &ntail are zero) + * header of skb. &sk_buff itself is not changed. &sk_buff MUST have + * reference count of 1. Returns zero in the case of success or error, + * if expansion failed. In the last case, &sk_buff is not changed. + * + * All the pointers pointing into skb header may change and must be + * reloaded after call to this function. + */ + +int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask) +{ + int i; + u8 *data; + int size = nhead + (skb->end - skb->head) + ntail; + long off; + + if (skb_shared(skb)) + BUG(); + + size = SKB_DATA_ALIGN(size); + + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (data == NULL) + goto nodata; + + /* Copy only real data... and, alas, header. This should be + * optimized for the cases when header is void. */ + memcpy(data+nhead, skb->head, skb->tail-skb->head); + memcpy(data+size, skb->end, sizeof(struct skb_shared_info)); + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) + get_page(skb_shinfo(skb)->frags[i].page); + + if (skb_shinfo(skb)->frag_list) + skb_clone_fraglist(skb); + + skb_release_data(skb); + + off = (data+nhead) - skb->head; + + skb->head = data; + skb->end = data+size; + + skb->data += off; + skb->tail += off; + skb->mac.raw += off; + skb->h.raw += off; + skb->nh.raw += off; + skb->cloned = 0; + atomic_set(&skb_shinfo(skb)->dataref, 1); + return 0; + +nodata: + return -ENOMEM; +} + +/* Make private copy of skb with writable head and some headroom */ + +struct sk_buff * +skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom) +{ + struct sk_buff *skb2; + int delta = headroom - skb_headroom(skb); + + if (delta <= 0) + return pskb_copy(skb, GFP_ATOMIC); + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2 == NULL || + !pskb_expand_head(skb2, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) + return skb2; + + kfree_skb(skb2); + return NULL; +} + + +/** * skb_copy_expand - copy and expand sk_buff * @skb: buffer to copy * @newheadroom: new free bytes at head @@ -439,7 +714,7 @@ * Allocate the copy buffer */ - n=alloc_skb(newheadroom + (skb->tail - skb->data) + newtailroom, + n=alloc_skb(newheadroom + skb->len + newtailroom, gfp_mask); if(n==NULL) return NULL; @@ -450,12 +725,431 @@ skb_put(n,skb->len); /* Copy the data only. */ - memcpy(n->data, skb->data, skb->len); + if (skb_copy_bits(skb, 0, n->data, skb->len)) + BUG(); copy_skb_header(n, skb); return n; } +/* Trims skb to length len. It can change skb pointers, if "realloc" is 1. + * If realloc==0 and trimming is impossible without change of data, + * it is BUG(). + */ + +int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc) +{ + int offset = skb_headlen(skb); + int nfrags = skb_shinfo(skb)->nr_frags; + int i; + + for (i=0; i<nfrags; i++) { + int end = offset + skb_shinfo(skb)->frags[i].size; + if (end > len) { + if (skb_cloned(skb)) { + if (!realloc) + BUG(); + if (!pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -ENOMEM; + } + if (len <= offset) { + put_page(skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb)->nr_frags--; + } else { + skb_shinfo(skb)->frags[i].size = len-offset; + } + } + offset = end; + } + + if (offset < len) { + skb->data_len -= skb->len - len; + skb->len = len; + } else { + if (len <= skb_headlen(skb)) { + skb->len = len; + skb->data_len = 0; + skb->tail = skb->data + len; + if (skb_shinfo(skb)->frag_list && !skb_cloned(skb)) + skb_drop_fraglist(skb); + } else { + skb->data_len -= skb->len - len; + skb->len = len; + } + } + + return 0; +} + +/** + * __pskb_pull_tail - advance tail of skb header + * @skb: buffer to reallocate + * @delta: number of bytes to advance tail + * + * The function makes a sense only on a fragmented &sk_buff, + * it expands header moving its tail forward and copying necessary + * data from fragmented part. + * + * &sk_buff MUST have reference count of 1. + * + * Returns %NULL (and &sk_buff does not change) if pull failed + * or value of new tail of skb in the case of success. + * + * All the pointers pointing into skb header may change and must be + * reloaded after call to this function. + */ + +/* Moves tail of skb head forward, copying data from fragmented part, + * when it is necessary. + * 1. It may fail due to malloc failure. + * 2. It may change skb pointers. + * + * It is pretty complicated. Luckily, it is called only in exceptional cases. + */ +unsigned char * __pskb_pull_tail(struct sk_buff *skb, int delta) +{ + int i, k, eat; + + /* If skb has not enough free space at tail, get new one + * plus 128 bytes for future expansions. If we have enough + * room at tail, reallocate without expansion only if skb is cloned. + */ + eat = (skb->tail+delta) - skb->end; + + if (eat > 0 || skb_cloned(skb)) { + if (pskb_expand_head(skb, 0, eat>0 ? eat+128 : 0, GFP_ATOMIC)) + return NULL; + } + + if (skb_copy_bits(skb, skb_headlen(skb), skb->tail, delta)) + BUG(); + + /* Optimization: no fragments, no reasons to preestimate + * size of pulled pages. Superb. + */ + if (skb_shinfo(skb)->frag_list == NULL) + goto pull_pages; + + /* Estimate size of pulled pages. */ + eat = delta; + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size >= eat) + goto pull_pages; + eat -= skb_shinfo(skb)->frags[i].size; + } + + /* If we need update frag list, we are in troubles. + * Certainly, it possible to add an offset to skb data, + * but taking into account that pulling is expected to + * be very rare operation, it is worth to fight against + * further bloating skb head and crucify ourselves here instead. + * Pure masohism, indeed. 8)8) + */ + if (eat) { + struct sk_buff *list = skb_shinfo(skb)->frag_list; + struct sk_buff *clone = NULL; + struct sk_buff *insp = NULL; + + do { + if (list == NULL) + BUG(); + + if (list->len <= eat) { + /* Eaten as whole. */ + eat -= list->len; + list = list->next; + insp = list; + } else { + /* Eaten partially. */ + + if (skb_shared(list)) { + /* Sucks! We need to fork list. :-( */ + clone = skb_clone(list, GFP_ATOMIC); + if (clone == NULL) + return NULL; + insp = list->next; + list = clone; + } else { + /* This may be pulled without + * problems. */ + insp = list; + } + if (pskb_pull(list, eat) == NULL) { + if (clone) + kfree_skb(clone); + return NULL; + } + break; + } + } while (eat); + + /* Free pulled out fragments. */ + while ((list = skb_shinfo(skb)->frag_list) != insp) { + skb_shinfo(skb)->frag_list = list->next; + kfree_skb(list); + } + /* And insert new clone at head. */ + if (clone) { + clone->next = list; + skb_shinfo(skb)->frag_list = clone; + } + } + /* Success! Now we may commit changes to skb data. */ + +pull_pages: + eat = delta; + k = 0; + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size <= eat) { + put_page(skb_shinfo(skb)->frags[i].page); + eat -= skb_shinfo(skb)->frags[i].size; + } else { + skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; + if (eat) { + skb_shinfo(skb)->frags[k].page_offset += eat; + skb_shinfo(skb)->frags[k].size -= eat; + eat = 0; + } + k++; + } + } + skb_shinfo(skb)->nr_frags = k; + + skb->tail += delta; + skb->data_len -= delta; + + return skb->tail; +} + +/* Copy some data bits from skb to kernel buffer. */ + +int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) +{ + int i, copy; + int start = skb->len - skb->data_len; + + if (offset > (int)skb->len-len) + goto fault; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + memcpy(to, skb->data + offset, copy); + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + u8 *vaddr; + + if (copy > len) + copy = len; + + vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]); + memcpy(to, vaddr+skb_shinfo(skb)->frags[i].page_offset+ + offset-start, copy); + kunmap_skb_frag(vaddr); + + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_bits(list, offset-start, to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + } + start = end; + } + } + if (len == 0) + return 0; + +fault: + return -EFAULT; +} + +/* Checksum skb data. */ + +unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum) +{ + int i, copy; + int start = skb->len - skb->data_len; + int pos = 0; + + /* Checksum header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + csum = csum_partial(skb->data+offset, copy, csum); + if ((len -= copy) == 0) + return csum; + offset += copy; + pos = copy; + } + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + unsigned int csum2; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + if (copy > len) + copy = len; + vaddr = kmap_skb_frag(frag); + csum2 = csum_partial(vaddr + frag->page_offset + + offset-start, copy, 0); + kunmap_skb_frag(vaddr); + csum = csum_block_add(csum, csum2, pos); + if (!(len -= copy)) + return csum; + offset += copy; + pos += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + unsigned int csum2; + if (copy > len) + copy = len; + csum2 = skb_checksum(list, offset-start, copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + pos += copy; + } + start = end; + } + } + if (len == 0) + return csum; + + BUG(); + return csum; +} + +/* Both of above in one bottle. */ + +unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum) +{ + int i, copy; + int start = skb->len - skb->data_len; + int pos = 0; + + /* Copy header. */ + if ((copy = start-offset) > 0) { + if (copy > len) + copy = len; + csum = csum_partial_copy_nocheck(skb->data+offset, to, copy, csum); + if ((len -= copy) == 0) + return csum; + offset += copy; + to += copy; + pos = copy; + } + + for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { + int end; + + BUG_TRAP(start <= offset+len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end-offset) > 0) { + unsigned int csum2; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + if (copy > len) + copy = len; + vaddr = kmap_skb_frag(frag); + csum2 = csum_partial_copy_nocheck(vaddr + frag->page_offset + + offset-start, to, copy, 0); + kunmap_skb_frag(vaddr); + csum = csum_block_add(csum, csum2, pos); + if (!(len -= copy)) + return csum; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { + unsigned int csum2; + int end; + + BUG_TRAP(start <= offset+len); + + end = start + list->len; + if ((copy = end-offset) > 0) { + if (copy > len) + copy = len; + csum2 = skb_copy_and_csum_bits(list, offset-start, to, copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + to += copy; + pos += copy; + } + start = end; + } + } + if (len == 0) + return csum; + + BUG(); + return csum; +} + + #if 0 /* * Tune the memory allocator for a new MTU size. @@ -463,7 +1157,7 @@ void skb_add_mtu(int mtu) { /* Must match allocation in alloc_skb */ - mtu = ((mtu + 15) & ~15) + sizeof(atomic_t); + mtu = SKB_DATA_ALIGN(mtu) + sizeof(struct skb_shared_info); kmem_add_cache_size(mtu); } diff -u --recursive --new-file v2.4.3/linux/net/core/sock.c linux/net/core/sock.c --- v2.4.3/linux/net/core/sock.c Sat Feb 3 11:26:44 2001 +++ linux/net/core/sock.c Thu Apr 12 12:11:39 2001 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.104 2001/01/30 07:48:30 davem Exp $ + * Version: $Id: sock.c,v 1.109 2001/03/03 01:20:10 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -79,6 +79,7 @@ * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER. * Andi Kleen : Add sock_kmalloc()/sock_kfree_s() * Andi Kleen : Fix write_space callback + * Chris Evans : Security fixes - signedness again * * To Fix: * @@ -425,11 +426,13 @@ struct timeval tm; } v; - int lv=sizeof(int),len; + unsigned int lv=sizeof(int),len; if(get_user(len,optlen)) return -EFAULT; - + if(len < 0) + return -EINVAL; + switch(optname) { case SO_DEBUG: @@ -727,6 +730,8 @@ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); add_wait_queue(sk->sleep, &wait); for (;;) { + if (!timeo) + break; if (signal_pending(current)) break; set_bit(SOCK_NOSPACE, &sk->socket->flags); @@ -750,7 +755,7 @@ */ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - unsigned long fallback, int noblock, int *errcode) + int noblock, int *errcode) { int err; struct sk_buff *skb; @@ -780,15 +785,6 @@ goto failure; if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) { - if (fallback) { - /* The buffer get won't block, or use the atomic queue. - * It does produce annoying no free page messages still. - */ - skb = alloc_skb(size, GFP_BUFFER); - if (skb) - break; - try_size = fallback; - } skb = alloc_skb(try_size, sk->allocation); if (skb) break; @@ -1064,6 +1060,36 @@ { /* Mirror missing mmap method error code */ return -ENODEV; +} + +ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) +{ + ssize_t res; + struct msghdr msg; + struct iovec iov; + mm_segment_t old_fs; + char *kaddr; + + kaddr = kmap(page); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = flags; + + iov.iov_base = kaddr + offset; + iov.iov_len = size; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + res = sock_sendmsg(sock, &msg, size); + set_fs(old_fs); + + kunmap(page); + return res; } /* diff -u --recursive --new-file v2.4.3/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.4.3/linux/net/decnet/af_decnet.c Sun Mar 25 18:14:25 2001 +++ linux/net/decnet/af_decnet.c Thu Apr 12 12:11:39 2001 @@ -2128,6 +2128,7 @@ sendmsg: dn_sendmsg, recvmsg: dn_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #ifdef CONFIG_SYSCTL diff -u --recursive --new-file v2.4.3/linux/net/econet/af_econet.c linux/net/econet/af_econet.c --- v2.4.3/linux/net/econet/af_econet.c Mon Oct 16 12:42:54 2000 +++ linux/net/econet/af_econet.c Thu Apr 12 12:11:39 2001 @@ -297,7 +297,7 @@ #ifdef CONFIG_ECONET_NATIVE atomic_inc(&dev->refcnt); - skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL) goto out_unlock; @@ -410,7 +410,7 @@ } /* Get a skbuff (no data, just holds our cb information) */ - if ((skb = sock_alloc_send_skb(sk, 0, 0, + if ((skb = sock_alloc_send_skb(sk, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; @@ -717,6 +717,7 @@ sendmsg: econet_sendmsg, recvmsg: econet_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --recursive --new-file v2.4.3/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.4.3/linux/net/ipv4/af_inet.c Fri Dec 29 14:07:24 2000 +++ linux/net/ipv4/af_inet.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.127 2000/12/22 19:51:50 davem Exp $ + * Version: $Id: af_inet.c,v 1.129 2001/03/02 03:13:05 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -355,6 +355,8 @@ else sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT; + sk->protinfo.af_inet.id = 0; + sock_init_data(sock,sk); sk->destruct = inet_sock_destruct; @@ -934,7 +936,8 @@ getsockopt: inet_getsockopt, sendmsg: inet_sendmsg, recvmsg: inet_recvmsg, - mmap: sock_no_mmap + mmap: sock_no_mmap, + sendpage: tcp_sendpage }; struct proto_ops inet_dgram_ops = { @@ -955,6 +958,7 @@ sendmsg: inet_sendmsg, recvmsg: inet_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family inet_family_ops = { diff -u --recursive --new-file v2.4.3/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.4.3/linux/net/ipv4/arp.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/arp.c Thu Apr 12 12:11:39 2001 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.90 2000/10/04 09:20:56 anton Exp $ + * Version: $Id: arp.c,v 1.96 2001/02/02 08:42:59 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -590,6 +590,13 @@ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out_of_mem; + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) + goto freeskb; + arp = skb->nh.arph; + arp_ptr= (unsigned char *)(arp+1); + } + switch (dev_type) { default: if (arp->ar_pro != __constant_htons(ETH_P_IP)) @@ -796,9 +803,10 @@ } out: - kfree_skb(skb); if (in_dev) in_dev_put(in_dev); +freeskb: + kfree_skb(skb); out_of_mem: return 0; } diff -u --recursive --new-file v2.4.3/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.4.3/linux/net/ipv4/icmp.c Fri Aug 4 18:18:49 2000 +++ linux/net/ipv4/icmp.c Thu Apr 12 12:11:39 2001 @@ -3,7 +3,7 @@ * * Alan Cox, <alan@redhat.com> * - * Version: $Id: icmp.c,v 1.71 2000/08/02 06:01:48 davem Exp $ + * Version: $Id: icmp.c,v 1.73 2000/12/13 18:31:48 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -58,197 +58,6 @@ * - Should use skb_pull() instead of all the manual checking. * This would also greatly simply some upper layer error handlers. --AK * - * RFC1122 (Host Requirements -- Comm. Layer) Status: - * (boy, are there a lot of rules for ICMP) - * 3.2.2 (Generic ICMP stuff) - * MUST discard messages of unknown type. (OK) - * MUST copy at least the first 8 bytes from the offending packet - * when sending ICMP errors. (OBSOLETE -- see RFC1812) - * MUST pass received ICMP errors up to protocol level. (OK) - * SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812) - * MUST NOT send ICMP errors in reply to: - * ICMP errors (OK) - * Broadcast/multicast datagrams (OK) - * MAC broadcasts (OK) - * Non-initial fragments (OK) - * Datagram with a source address that isn't a single host. (OK) - * 3.2.2.1 (Destination Unreachable) - * All the rules govern the IP layer, and are dealt with in ip.c, not here. - * 3.2.2.2 (Redirect) - * Host SHOULD NOT send ICMP_REDIRECTs. (OK) - * MUST update routing table in response to host or network redirects. - * (host OK, network OBSOLETE) - * SHOULD drop redirects if they're not from directly connected gateway - * (OK -- we drop it if it's not from our old gateway, which is close - * enough) - * 3.2.2.3 (Source Quench) - * MUST pass incoming SOURCE_QUENCHs to transport layer (OK) - * Other requirements are dealt with at the transport layer. - * 3.2.2.4 (Time Exceeded) - * MUST pass TIME_EXCEEDED to transport layer (OK) - * Other requirements dealt with at IP (generating TIME_EXCEEDED). - * 3.2.2.5 (Parameter Problem) - * SHOULD generate these (OK) - * MUST pass received PARAMPROBLEM to transport layer (NOT YET) - * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC - * 3.2.2.6 (Echo Request/Reply) - * MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK) - * MAY discard broadcast ECHO_REQUESTs. (Configurable with a sysctl.) - * MUST reply using same source address as the request was sent to. - * We're OK for unicast ECHOs, and it doesn't say anything about - * how to handle broadcast ones, since it's optional. - * MUST copy data from REQUEST to REPLY (OK) - * unless it would require illegal fragmentation (OK) - * MUST pass REPLYs to transport/user layer (OK) - * MUST use any provided source route (reversed) for REPLY. (NOT YET) - * 3.2.2.7 (Information Request/Reply) - * MUST NOT implement this. (I guess that means silently discard...?) (OK) - * 3.2.2.8 (Timestamp Request/Reply) - * MAY implement (OK) - * SHOULD be in-kernel for "minimum variability" (OK) - * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency) - * MUST reply using same source address as the request was sent to. (OK) - * MUST reverse source route, as per ECHO (NOT YET) - * MUST pass REPLYs to transport/user layer (requires RAW, just like - * ECHO) (OK) - * MUST update clock for timestamp at least 15 times/sec (OK) - * MUST be "correct within a few minutes" (OK) - * 3.2.2.9 (Address Mask Request/Reply) - * MAY implement (OK) - * MUST send a broadcast REQUEST if using this system to set netmask - * (OK... we don't use it) - * MUST discard received REPLYs if not using this system (OK) - * MUST NOT send replies unless specifically made agent for this sort - * of thing. (OK) - * - * - * RFC 1812 (IPv4 Router Requirements) Status (even longer): - * 4.3.2.1 (Unknown Message Types) - * MUST pass messages of unknown type to ICMP user iface or silently discard - * them (OK) - * 4.3.2.2 (ICMP Message TTL) - * MUST initialize TTL when originating an ICMP message (OK) - * 4.3.2.3 (Original Message Header) - * SHOULD copy as much data from the offending packet as possible without - * the length of the ICMP datagram exceeding 576 bytes (OK) - * MUST leave original IP header of the offending packet, but we're not - * required to undo modifications made (OK) - * 4.3.2.4 (Original Message Source Address) - * MUST use one of addresses for the interface the orig. packet arrived as - * source address (OK) - * 4.3.2.5 (TOS and Precedence) - * SHOULD leave TOS set to the same value unless the packet would be - * discarded for that reason (OK) - * MUST use TOS=0 if not possible to leave original value (OK) - * MUST leave IP Precedence for Source Quench messages (OK -- not sent - * at all) - * SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control) - * for all other error messages (OK, we use 6) - * MAY allow configuration of IP Precedence (OK -- not done) - * MUST leave IP Precedence and TOS for reply messages (OK) - * 4.3.2.6 (Source Route) - * SHOULD use reverse source route UNLESS sending Parameter Problem on source - * routing and UNLESS the packet would be immediately discarded (NOT YET) - * 4.3.2.7 (When Not to Send ICMP Errors) - * MUST NOT send ICMP errors in reply to: - * ICMP errors (OK) - * Packets failing IP header validation tests unless otherwise noted (OK) - * Broadcast/multicast datagrams (OK) - * MAC broadcasts (OK) - * Non-initial fragments (OK) - * Datagram with a source address that isn't a single host. (OK) - * 4.3.2.8 (Rate Limiting) - * SHOULD be able to limit error message rate (OK) - * SHOULD allow setting of rate limits (OK, in the source) - * 4.3.3.1 (Destination Unreachable) - * All the rules govern the IP layer, and are dealt with in ip.c, not here. - * 4.3.3.2 (Redirect) - * MAY ignore ICMP Redirects if running a routing protocol or if forwarding - * is enabled on the interface (OK -- ignores) - * 4.3.3.3 (Source Quench) - * SHOULD NOT originate SQ messages (OK) - * MUST be able to limit SQ rate if originates them (OK as we don't - * send them) - * MAY ignore SQ messages it receives (OK -- we don't) - * 4.3.3.4 (Time Exceeded) - * Requirements dealt with at IP (generating TIME_EXCEEDED). - * 4.3.3.5 (Parameter Problem) - * MUST generate these for all errors not covered by other messages (OK) - * MUST include original value of the value pointed by (OK) - * 4.3.3.6 (Echo Request) - * MUST implement echo server function (OK) - * MUST process at ER of at least max(576, MTU) (OK) - * MAY reject broadcast/multicast ER's (We don't, but that's OK) - * SHOULD have a config option for silently ignoring ER's (OK) - * MUST have a default value for the above switch = NO (OK) - * MUST have application layer interface for Echo Request/Reply (OK) - * MUST reply using same source address as the request was sent to. - * We're OK for unicast ECHOs, and it doesn't say anything about - * how to handle broadcast ones, since it's optional. - * MUST copy data from Request to Reply (OK) - * SHOULD update Record Route / Timestamp options (??) - * MUST use reversed Source Route for Reply if possible (NOT YET) - * 4.3.3.7 (Information Request/Reply) - * SHOULD NOT originate or respond to these (OK) - * 4.3.3.8 (Timestamp / Timestamp Reply) - * MAY implement (OK) - * MUST reply to every Timestamp message received (OK) - * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency) - * MUST reply using same source address as the request was sent to. (OK) - * MUST use reversed Source Route if possible (NOT YET) - * SHOULD update Record Route / Timestamp options (??) - * MUST pass REPLYs to transport/user layer (requires RAW, just like - * ECHO) (OK) - * MUST update clock for timestamp at least 16 times/sec (OK) - * MUST be "correct within a few minutes" (OK) - * 4.3.3.9 (Address Mask Request/Reply) - * MUST have support for receiving AMRq and responding with AMRe (OK, - * but only as a compile-time option) - * SHOULD have option for each interface for AMRe's, MUST default to - * NO (NOT YET) - * MUST NOT reply to AMRq before knows the correct AM (OK) - * MUST NOT respond to AMRq with source address 0.0.0.0 on physical - * interfaces having multiple logical i-faces with different masks - * (NOT YET) - * SHOULD examine all AMRe's it receives and check them (NOT YET) - * SHOULD log invalid AMRe's (AM+sender) (NOT YET) - * MUST NOT use contents of AMRe to determine correct AM (OK) - * MAY broadcast AMRe's after having configured address masks (OK -- doesn't) - * MUST NOT do broadcast AMRe's if not set by extra option (OK, no option) - * MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK) - * 4.3.3.10 (Router Advertisement and Solicitations) - * MUST support router part of Router Discovery Protocol on all networks we - * support broadcast or multicast addressing. (OK -- done by gated) - * MUST have all config parameters with the respective defaults (OK) - * 5.2.7.1 (Destination Unreachable) - * MUST generate DU's (OK) - * SHOULD choose a best-match response code (OK) - * SHOULD NOT generate Host Isolated codes (OK) - * SHOULD use Communication Administratively Prohibited when administratively - * filtering packets (NOT YET -- bug-to-bug compatibility) - * MAY include config option for not generating the above and silently - * discard the packets instead (OK) - * MAY include config option for not generating Precedence Violation and - * Precedence Cutoff messages (OK as we don't generate them at all) - * MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts - * on the same network might be reachable (OK -- no net unreach's at all) - * MUST use new form of Fragmentation Needed and DF Set messages (OK) - * 5.2.7.2 (Redirect) - * MUST NOT generate network redirects (OK) - * MUST be able to generate host redirects (OK) - * SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS) - * MUST have an option to use Host redirects instead of Host+TOS ones (OK as - * no Host+TOS Redirects are used) - * MUST NOT generate redirects unless forwarding to the same i-face and the - * dest. address is on the same subnet as the src. address and no source - * routing is in use. (OK) - * MUST NOT follow redirects when using a routing protocol (OK) - * MAY use redirects if not using a routing protocol (OK, compile-time option) - * MUST comply to Host Requirements when not acting as a router (OK) - * 5.2.7.3 (Time Exceeded) - * MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK) - * MAY have a per-interface option to disable origination of TE messages, but - * it MUST default to "originate" (OK -- we don't support it) */ #include <linux/config.h> @@ -282,6 +91,26 @@ #define min(a,b) ((a)<(b)?(a):(b)) /* + * Build xmit assembly blocks + */ + +struct icmp_bxm +{ + struct sk_buff *skb; + int offset; + int data_len; + + unsigned int csum; + struct { + struct icmphdr icmph; + __u32 times[3]; + } data; + int head_len; + struct ip_options replyopts; + unsigned char optbuf[40]; +}; + +/* * Statistics */ @@ -324,7 +153,7 @@ { unsigned long *output; /* Address to increment on output */ unsigned long *input; /* Address to increment on input */ - void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len); + void (*handler)(struct sk_buff *skb); short error; /* This ICMP is classed as an error message */ int *timeout; /* Rate limit */ }; @@ -466,11 +295,12 @@ { struct icmp_bxm *icmp_param = (struct icmp_bxm *)p; struct icmphdr *icmph; - unsigned long csum; + unsigned int csum; if (offset) { - icmp_param->csum=csum_partial_copy_nocheck(icmp_param->data_ptr+offset-sizeof(struct icmphdr), - to, fraglen,icmp_param->csum); + icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb, + icmp_param->offset+(offset-icmp_param->head_len), + to, fraglen,icmp_param->csum); return 0; } @@ -479,22 +309,24 @@ * the other fragments first, so that we get the checksum * for the whole packet here. */ - csum = csum_partial_copy_nocheck((void *)&icmp_param->icmph, - to, sizeof(struct icmphdr), + csum = csum_partial_copy_nocheck((void *)&icmp_param->data, + to, icmp_param->head_len, icmp_param->csum); - csum = csum_partial_copy_nocheck(icmp_param->data_ptr, - to+sizeof(struct icmphdr), - fraglen-sizeof(struct icmphdr), csum); + csum=skb_copy_and_csum_bits(icmp_param->skb, + icmp_param->offset, + to+icmp_param->head_len, + fraglen-icmp_param->head_len, + csum); icmph=(struct icmphdr *)to; icmph->checksum = csum_fold(csum); return 0; } - + /* * Driving logic for building and sending ICMP messages. */ -void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) +static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct sock *sk=icmp_socket->sk; struct ipcm_cookie ipc; @@ -507,9 +339,9 @@ if (icmp_xmit_lock_bh()) return; - icmp_param->icmph.checksum=0; + icmp_param->data.icmph.checksum=0; icmp_param->csum=0; - icmp_out_count(icmp_param->icmph.type); + icmp_out_count(icmp_param->data.icmph.type); sk->protinfo.af_inet.tos = skb->nh.iph->tos; daddr = ipc.addr = rt->rt_src; @@ -521,10 +353,10 @@ } if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) goto out; - if (icmpv4_xrlim_allow(rt, icmp_param->icmph.type, - icmp_param->icmph.code)) { + if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, + icmp_param->data.icmph.code)) { ip_build_xmit(sk, icmp_glue_bits, icmp_param, - icmp_param->data_len+sizeof(struct icmphdr), + icmp_param->data_len+icmp_param->head_len, &ipc, rt, MSG_DONTWAIT); } ip_rt_put(rt); @@ -543,10 +375,9 @@ * MUST reply to only the first fragment. */ -void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info) +void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) { struct iphdr *iph; - struct icmphdr *icmph; int room; struct icmp_bxm icmp_param; struct rtable *rt = (struct rtable*)skb_in->dst; @@ -558,10 +389,15 @@ return; /* - * Find the original header + * Find the original header. It is expected to be valid, of course. + * Check this, icmp_send is called from the most obscure devices + * sometimes. */ iph = skb_in->nh.iph; + if ((u8*)iph < skb_in->head || (u8*)(iph+1) > skb_in->tail) + return; + /* * No replies to physical multicast/broadcast */ @@ -589,17 +425,24 @@ * We are an error, check if we are replying to an ICMP error */ if (iph->protocol==IPPROTO_ICMP) { - icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); + u8 inner_type; + + if (skb_copy_bits(skb_in, + skb_in->nh.raw + (iph->ihl<<2) + + offsetof(struct icmphdr, type) + - skb_in->data, + &inner_type, 1)) + return; + /* * Assume any unknown ICMP type is an error. This isn't * specified by the RFC, but think about it.. */ - if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error) + if (inner_type>NR_ICMP_TYPES || icmp_pointers[inner_type].error) return; } } - if (icmp_xmit_lock()) return; @@ -625,12 +468,6 @@ ((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) : iph->tos; - /* XXX: use a more aggressive expire for routes created by - * this call (not longer than the rate limit timeout). - * It could be also worthwhile to not put them into ipv4 - * fast routing cache at first. Otherwise an attacker can - * grow the routing table. - */ if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) goto out; @@ -642,13 +479,14 @@ * Prepare data for ICMP header. */ - icmp_param.icmph.type=type; - icmp_param.icmph.code=code; - icmp_param.icmph.un.gateway = info; - icmp_param.icmph.checksum=0; + icmp_param.data.icmph.type=type; + icmp_param.data.icmph.code=code; + icmp_param.data.icmph.un.gateway = info; + icmp_param.data.icmph.checksum=0; icmp_param.csum=0; - icmp_param.data_ptr=iph; - icmp_out_count(icmp_param.icmph.type); + icmp_param.skb=skb_in; + icmp_param.offset=skb_in->nh.raw - skb_in->data; + icmp_out_count(icmp_param.data.icmph.type); icmp_socket->sk->protinfo.af_inet.tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; @@ -669,10 +507,11 @@ room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen; room -= sizeof(struct icmphdr); - icmp_param.data_len=(skb_in->tail-(u8*)iph); + icmp_param.data_len=skb_in->len-icmp_param.offset; if (icmp_param.data_len > room) icmp_param.data_len = room; - + icmp_param.head_len = sizeof(struct icmphdr); + ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param, icmp_param.data_len+sizeof(struct icmphdr), &ipc, rt, MSG_DONTWAIT); @@ -688,28 +527,35 @@ * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. */ -static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_unreach(struct sk_buff *skb) { struct iphdr *iph; - int hash; + struct icmphdr *icmph; + int hash, protocol; struct inet_protocol *ipprot; - unsigned char *dp; struct sock *raw_sk; - + u32 info = 0; + /* * Incomplete header ? * Only checks for the IP header, there should be an * additional check for longer headers in upper levels. */ - if(len<sizeof(struct iphdr)) { + if (!pskb_may_pull(skb, sizeof(struct iphdr))) { ICMP_INC_STATS_BH(IcmpInErrors); return; } - - iph = (struct iphdr *) (icmph + 1); - dp = (unsigned char*)iph; - + + icmph = skb->h.icmph; + iph = (struct iphdr *) skb->data; + + if (iph->ihl<5) { + /* Mangled header, drop. */ + ICMP_INC_STATS_BH(IcmpInErrors); + return; + } + if(icmph->type==ICMP_DEST_UNREACH) { switch(icmph->code & 15) { case ICMP_NET_UNREACH: @@ -726,11 +572,9 @@ printk(KERN_INFO "ICMP: %u.%u.%u.%u: fragmentation needed and DF set.\n", NIPQUAD(iph->daddr)); } else { - unsigned short new_mtu; - new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu)); - if (!new_mtu) - return; - icmph->un.frag.mtu = htons(new_mtu); + info = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu)); + if (!info) + goto out; } break; case ICMP_SR_FAILED: @@ -740,10 +584,12 @@ default: break; } - if (icmph->code>NR_ICMP_UNREACH) - return; + if (icmph->code>NR_ICMP_UNREACH) + goto out; + } else if (icmph->type == ICMP_PARAMETERPROB) { + info = ntohl(icmph->un.gateway)>>24; } - + /* * Throw it at our lower layers * @@ -751,7 +597,7 @@ * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer. * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer. */ - + /* * Check the other end isnt violating RFC 1122. Some routers send * bogus responses to broadcast frames. If you see this message @@ -767,23 +613,33 @@ if (net_ratelimit()) printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP error to a broadcast.\n", NIPQUAD(skb->nh.iph->saddr)); - return; + goto out; } } + /* Checkin full IP header plus 8 bytes of protocol to + * avoid additional coding at protocol handlers. + */ + if (!pskb_may_pull(skb, iph->ihl*4+8)) + goto out; + + iph = (struct iphdr *) skb->data; + protocol = iph->protocol; + /* * Deliver ICMP message to raw sockets. Pretty useless feature? */ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ - hash = iph->protocol & (MAX_INET_PROTOS - 1); + hash = protocol & (MAX_INET_PROTOS - 1); read_lock(&raw_v4_lock); if ((raw_sk = raw_v4_htable[hash]) != NULL) { - while ((raw_sk = __raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, + while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->saddr, iph->daddr, skb->dev->ifindex)) != NULL) { - raw_err(raw_sk, skb); + raw_err(raw_sk, skb, info); raw_sk = raw_sk->next; + iph = (struct iphdr *)skb->data; } } read_unlock(&raw_v4_lock); @@ -807,11 +663,12 @@ /* RFC1122: OK. Passes appropriate ICMP errors to the */ /* appropriate protocol layer (MUST), as per 3.2.2. */ - if (iph->protocol == ipprot->protocol && ipprot->err_handler) - ipprot->err_handler(skb, dp, len); + if (protocol == ipprot->protocol && ipprot->err_handler) + ipprot->err_handler(skb, info); ipprot = nextip; } +out: } @@ -819,24 +676,26 @@ * Handle ICMP_REDIRECT. */ -static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_redirect(struct sk_buff *skb) { struct iphdr *iph; unsigned long ip; - if (len < sizeof(struct iphdr)) { + if (skb->len < sizeof(struct iphdr)) { ICMP_INC_STATS_BH(IcmpInErrors); return; } - + /* * Get the copied header of the packet that caused the redirect */ - - iph = (struct iphdr *) (icmph + 1); + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + return; + + iph = (struct iphdr *) skb->data; ip = iph->daddr; - switch(icmph->code & 7) { + switch(skb->h.icmph->code & 7) { case ICMP_REDIR_NET: case ICMP_REDIR_NETTOS: /* @@ -846,7 +705,7 @@ case ICMP_REDIR_HOST: case ICMP_REDIR_HOSTTOS: - ip_rt_redirect(skb->nh.iph->saddr, ip, icmph->un.gateway, iph->saddr, iph->tos, skb->dev); + ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway, iph->saddr, iph->tos, skb->dev); break; default: break; @@ -862,15 +721,17 @@ * See also WRT handling of options once they are done and working. */ -static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_echo(struct sk_buff *skb) { if (!sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; - icmp_param.icmph=*icmph; - icmp_param.icmph.type=ICMP_ECHOREPLY; - icmp_param.data_ptr=(icmph+1); - icmp_param.data_len=len; + icmp_param.data.icmph=*skb->h.icmph; + icmp_param.data.icmph.type=ICMP_ECHOREPLY; + icmp_param.skb=skb; + icmp_param.offset=0; + icmp_param.data_len=skb->len; + icmp_param.head_len=sizeof(struct icmphdr); icmp_reply(&icmp_param, skb); } } @@ -883,34 +744,35 @@ * MUST be updated at least at 15Hz. */ -static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_timestamp(struct sk_buff *skb) { struct timeval tv; - __u32 times[3]; /* So the new timestamp works on ALPHA's.. */ struct icmp_bxm icmp_param; /* * Too short. */ - if(len<12) { + if(skb->len<4) { ICMP_INC_STATS_BH(IcmpInErrors); return; } - + /* * Fill in the current time as ms since midnight UT: */ - do_gettimeofday(&tv); - times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); - times[2] = times[1]; - memcpy((void *)×[0], icmph+1, 4); /* Incoming stamp */ - icmp_param.icmph=*icmph; - icmp_param.icmph.type=ICMP_TIMESTAMPREPLY; - icmp_param.icmph.code=0; - icmp_param.data_ptr=× - icmp_param.data_len=12; + icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); + icmp_param.data.times[2] = icmp_param.data.times[1]; + if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)) + BUG(); + icmp_param.data.icmph=*skb->h.icmph; + icmp_param.data.icmph.type=ICMP_TIMESTAMPREPLY; + icmp_param.data.icmph.code=0; + icmp_param.skb=skb; + icmp_param.offset=0; + icmp_param.data_len=0; + icmp_param.head_len=sizeof(struct icmphdr)+12; icmp_reply(&icmp_param, skb); } @@ -948,7 +810,7 @@ * anyway... */ -static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_address(struct sk_buff *skb) { #if 0 if (net_ratelimit()) @@ -961,7 +823,7 @@ * loudly if an inconsistency is found. */ -static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_address_reply(struct sk_buff *skb) { struct rtable *rt = (struct rtable*)skb->dst; struct net_device *dev = skb->dev; @@ -969,7 +831,7 @@ struct in_ifaddr *ifa; u32 mask; - if (len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) + if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) return; in_dev = in_dev_get(dev); @@ -979,8 +841,8 @@ if (in_dev->ifa_list && IN_DEV_LOG_MARTIANS(in_dev) && IN_DEV_FORWARD(in_dev)) { - - mask = *(u32*)&icmph[1]; + if (skb_copy_bits(skb, 0, &mask, 4)) + BUG(); for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa)) break; @@ -994,7 +856,7 @@ in_dev_put(in_dev); } -static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len) +static void icmp_discard(struct sk_buff *skb) { } @@ -1002,23 +864,36 @@ * Deal with incoming ICMP packets. */ -int icmp_rcv(struct sk_buff *skb, unsigned short len) +int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph = skb->h.icmph; struct rtable *rt = (struct rtable*)skb->dst; ICMP_INC_STATS_BH(IcmpInMsgs); + switch (skb->ip_summed) { + case CHECKSUM_HW: + if ((u16)csum_fold(skb->csum) == 0) + break; + NETDEBUG(printk(KERN_DEBUG "icmp v4 hw csum failure\n")); + case CHECKSUM_NONE: + if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) + goto error; + default: + } + + if (!pskb_pull(skb, sizeof(struct icmphdr))) + goto error; + /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. */ - if(len < sizeof(struct icmphdr) || - ip_compute_csum((unsigned char *) icmph, len) || - icmph->type > NR_ICMP_TYPES) + if (icmph->type > NR_ICMP_TYPES) goto error; - + + /* * Parse the ICMP message */ @@ -1042,9 +917,8 @@ } } - len -= sizeof(struct icmphdr); icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++; - (icmp_pointers[icmph->type].handler)(icmph, skb, len); + (icmp_pointers[icmph->type].handler)(skb); drop: kfree_skb(skb); diff -u --recursive --new-file v2.4.3/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.4.3/linux/net/ipv4/igmp.c Tue Jan 9 10:54:57 2001 +++ linux/net/ipv4/igmp.c Thu Apr 12 12:11:39 2001 @@ -8,7 +8,7 @@ * the older version didn't come out right using gcc 2.5.8, the newer one * seems to fall out with gcc 2.6.2. * - * Version: $Id: igmp.c,v 1.41 2000/08/31 23:39:12 davem Exp $ + * Version: $Id: igmp.c,v 1.45 2001/02/23 06:32:11 davem Exp $ * * Authors: * Alan Cox <Alan.Cox@linux.org> @@ -235,7 +235,7 @@ iph->saddr = rt->rt_src; iph->protocol = IPPROTO_IGMP; iph->tot_len = htons(IGMP_SIZE); - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, NULL); ((u8*)&iph[1])[0] = IPOPT_RA; ((u8*)&iph[1])[1] = 4; ((u8*)&iph[1])[2] = 0; @@ -341,23 +341,32 @@ read_unlock(&in_dev->lock); } -int igmp_rcv(struct sk_buff *skb, unsigned short len) +int igmp_rcv(struct sk_buff *skb) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih = skb->h.igmph; struct in_device *in_dev = in_dev_get(skb->dev); + int len = skb->len; if (in_dev==NULL) { kfree_skb(skb); return 0; } + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + ih = skb->h.igmph; + } + if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) { in_dev_put(in_dev); kfree_skb(skb); return 0; } - + switch (ih->type) { case IGMP_HOST_MEMBERSHIP_QUERY: igmp_heard_query(in_dev, ih->code, ih->group); @@ -372,7 +381,7 @@ case IGMP_PIM: #ifdef CONFIG_IP_PIMSM_V1 in_dev_put(in_dev); - return pim_rcv_v1(skb, len); + return pim_rcv_v1(skb); #endif case IGMP_DVMRP: case IGMP_TRACE: diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.4.3/linux/net/ipv4/ip_forward.c Fri Oct 27 11:03:14 2000 +++ linux/net/ipv4/ip_forward.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * The IP forwarding functionality. * - * Version: $Id: ip_forward.c,v 1.47 2000/10/24 22:54:26 davem Exp $ + * Version: $Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $ * * Authors: see ip.c * @@ -83,6 +83,8 @@ if (skb->pkt_type != PACKET_HOST) goto drop; + + skb->ip_summed = CHECKSUM_NONE; /* * According to the RFC, we must first decrease the TTL field. If @@ -116,10 +118,9 @@ ip_rt_send_redirect(skb); /* We are about to mangle packet. Copy it! */ - if ((skb = skb_cow(skb, dev2->hard_header_len)) == NULL) - return NET_RX_DROP; + if (skb_cow(skb, dev2->hard_header_len)) + goto drop; iph = skb->nh.iph; - opt = &(IPCB(skb)->opt); /* Decrease ttl after skb cow done */ ip_decrease_ttl(iph); diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.4.3/linux/net/ipv4/ip_fragment.c Sun Mar 25 18:14:25 2001 +++ linux/net/ipv4/ip_fragment.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.53 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: ip_fragment.c,v 1.57 2001/03/07 22:00:57 davem Exp $ * * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox <Alan.Cox@linux.org> @@ -83,7 +83,8 @@ atomic_t refcnt; struct timer_list timer; /* when will this queue expire? */ struct ipq **pprev; - int iif; /* Device index - for icmp replies */ + int iif; + struct timeval stamp; }; /* Hash table. */ @@ -255,7 +256,6 @@ if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) { struct sk_buff *head = qp->fragments; - /* Send an ICMP "Fragment Reassembly Timeout" message. */ if ((head->dev = dev_get_by_index(qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); @@ -370,7 +370,6 @@ /* Add new segment to existing queue. */ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; struct sk_buff *prev, *next; int flags, offset; int ihl, end; @@ -378,14 +377,14 @@ if (qp->last_in & COMPLETE) goto err; - offset = ntohs(iph->frag_off); + offset = ntohs(skb->nh.iph->frag_off); flags = offset & ~IP_OFFSET; offset &= IP_OFFSET; offset <<= 3; /* offset is in 8-byte chunks */ - ihl = iph->ihl * 4; + ihl = skb->nh.iph->ihl * 4; /* Determine the position of this fragment. */ - end = offset + (ntohs(iph->tot_len) - ihl); + end = offset + skb->len - ihl; /* Is this the final fragment? */ if ((flags & IP_MF) == 0) { @@ -413,9 +412,10 @@ if (end == offset) goto err; - /* Point into the IP datagram 'data' part. */ - skb_pull(skb, (skb->nh.raw+ihl) - skb->data); - skb_trim(skb, end - offset); + if (pskb_pull(skb, ihl) == NULL) + goto err; + if (pskb_trim(skb, end-offset)) + goto err; /* Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put @@ -439,7 +439,8 @@ offset += i; if (end <= offset) goto err; - skb_pull(skb, i); + if (!pskb_pull(skb, i)) + goto err; if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->ip_summed = CHECKSUM_NONE; } @@ -452,8 +453,9 @@ /* Eat head of the next overlapped fragment * and leave the loop. The next ones cannot overlap. */ + if (!pskb_pull(next, i)) + goto err; FRAG_CB(next)->offset += i; - skb_pull(next, i); qp->meat -= i; if (next->ip_summed != CHECKSUM_UNNECESSARY) next->ip_summed = CHECKSUM_NONE; @@ -485,9 +487,10 @@ else qp->fragments = skb; - if (skb->dev) - qp->iif = skb->dev->ifindex; + if (skb->dev) + qp->iif = skb->dev->ifindex; skb->dev = NULL; + qp->stamp = skb->stamp; qp->meat += skb->len; atomic_add(skb->truesize, &ip_frag_mem); if (offset == 0) @@ -500,15 +503,10 @@ } -/* Build a new IP datagram from all its fragments. - * - * FIXME: We copy here because we lack an effective way of handling lists - * of bits on input. Until the new skb data handling is in I'm not going - * to touch this with a bargepole. - */ +/* Build a new IP datagram from all its fragments. */ + static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) { - struct sk_buff *skb; struct iphdr *iph; struct sk_buff *fp, *head = qp->fragments; int len; @@ -526,61 +524,58 @@ if(len > 65535) goto out_oversize; - skb = dev_alloc_skb(len); - if (!skb) + /* Head of list must not be cloned. */ + if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) goto out_nomem; - /* Fill in the basic details. */ - skb->mac.raw = skb->data; - skb->nh.raw = skb->data; - FRAG_CB(skb)->h = FRAG_CB(head)->h; - skb->ip_summed = head->ip_summed; - skb->csum = 0; - - /* Copy the original IP headers into the new buffer. */ - memcpy(skb_put(skb, ihlen), head->nh.iph, ihlen); - - /* Copy the data portions of all fragments into the new buffer. */ - for (fp=head; fp; fp = fp->next) { - memcpy(skb_put(skb, fp->len), fp->data, fp->len); - - if (skb->ip_summed != fp->ip_summed) - skb->ip_summed = CHECKSUM_NONE; - else if (skb->ip_summed == CHECKSUM_HW) - skb->csum = csum_add(skb->csum, fp->csum); - } - - skb->dst = dst_clone(head->dst); - skb->pkt_type = head->pkt_type; - skb->protocol = head->protocol; - skb->dev = dev; - - /* - * Clearly bogus, because security markings of the individual - * fragments should have been checked for consistency before - * gluing, and intermediate coalescing of fragments may have - * taken place in ip_defrag() before ip_glue() ever got called. - * If we're not going to do the consistency checking, we might - * as well take the value associated with the first fragment. - * --rct - */ - skb->security = head->security; - -#ifdef CONFIG_NETFILTER - /* Connection association is same as fragment (if any). */ - skb->nfct = head->nfct; - nf_conntrack_get(skb->nfct); -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = head->nf_debug; -#endif -#endif + /* If the first fragment is fragmented itself, we split + * it to two chunks: the first with data and paged part + * and the second, holding only fragments. */ + if (skb_shinfo(head)->frag_list) { + struct sk_buff *clone; + int i, plen = 0; + + if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) + goto out_nomem; + clone->next = head->next; + head->next = clone; + skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; + skb_shinfo(head)->frag_list = NULL; + for (i=0; i<skb_shinfo(head)->nr_frags; i++) + plen += skb_shinfo(head)->frags[i].size; + clone->len = clone->data_len = head->data_len - plen; + head->data_len -= clone->len; + head->len -= clone->len; + clone->csum = 0; + clone->ip_summed = head->ip_summed; + atomic_add(clone->truesize, &ip_frag_mem); + } - /* Done with all fragments. Fixup the new IP header. */ - iph = skb->nh.iph; + skb_shinfo(head)->frag_list = head->next; + skb_push(head, head->data - head->nh.raw); + atomic_sub(head->truesize, &ip_frag_mem); + + for (fp=head->next; fp; fp = fp->next) { + head->data_len += fp->len; + head->len += fp->len; + if (head->ip_summed != fp->ip_summed) + head->ip_summed = CHECKSUM_NONE; + else if (head->ip_summed == CHECKSUM_HW) + head->csum = csum_add(head->csum, fp->csum); + head->truesize += fp->truesize; + atomic_sub(fp->truesize, &ip_frag_mem); + } + + head->next = NULL; + head->dev = dev; + head->stamp = qp->stamp; + + iph = head->nh.iph; iph->frag_off = 0; iph->tot_len = htons(len); IP_INC_STATS_BH(IpReasmOKs); - return skb; + qp->fragments = NULL; + return head; out_nomem: NETDEBUG(printk(KERN_ERR diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c --- v2.4.3/linux/net/ipv4/ip_gre.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv4/ip_gre.c Thu Apr 12 12:11:39 2001 @@ -313,7 +313,7 @@ } -void ipgre_err(struct sk_buff *skb, unsigned char *dp, int len) +void ipgre_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -330,8 +330,8 @@ by themself??? */ - struct iphdr *iph = (struct iphdr*)dp; - u16 *p = (u16*)(dp+(iph->ihl<<2)); + struct iphdr *iph = (struct iphdr*)skb->data; + u16 *p = (u16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; int type = skb->h.icmph->type; int code = skb->h.icmph->code; @@ -350,7 +350,7 @@ } /* If only 8 bytes returned, keyed message will be dropped here */ - if (len < grehlen) + if (skb_headlen(skb) < grehlen) return; switch (type) { @@ -559,17 +559,24 @@ #endif } -int ipgre_rcv(struct sk_buff *skb, unsigned short len) +int ipgre_rcv(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; - u8 *h = skb->h.raw; - u16 flags = *(u16*)h; + struct iphdr *iph; + u8 *h; + u16 flags; u16 csum = 0; u32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; + if (!pskb_may_pull(skb, 16)) + goto drop_nolock; + + iph = skb->nh.iph; + h = skb->data; + flags = *(u16*)h; + if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. - We do not support routing headers. @@ -578,7 +585,16 @@ goto drop_nolock; if (flags&GRE_CSUM) { - csum = ip_compute_csum(h, len); + if (skb->ip_summed == CHECKSUM_HW) { + csum = (u16)csum_fold(skb->csum); + if (csum) + skb->ip_summed = CHECKSUM_NONE; + } + if (skb->ip_summed == CHECKSUM_NONE) { + skb->csum = skb_checksum(skb, 0, skb->len, 0); + skb->ip_summed = CHECKSUM_HW; + csum = (u16)csum_fold(skb->csum); + } offset += 4; } if (flags&GRE_KEY) { @@ -594,9 +610,11 @@ read_lock(&ipgre_lock); if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb_pull(skb, h + offset - skb->data); + skb->nh.raw = __pskb_pull(skb, offset); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - skb->ip_summed = 0; + if (skb->ip_summed == CHECKSUM_HW) + skb->csum = csum_sub(skb->csum, + csum_partial(skb->mac.raw, skb->nh.raw-skb->mac.raw, 0)); skb->protocol = *(u16*)(h + 2); skb->pkt_type = PACKET_HOST; #ifdef CONFIG_NET_IPGRE_BROADCAST @@ -1263,14 +1281,7 @@ printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel; -#ifdef MODULE register_netdev(&ipgre_fb_tunnel_dev); -#else - rtnl_lock(); - register_netdevice(&ipgre_fb_tunnel_dev); - rtnl_unlock(); -#endif - inet_add_protocol(&ipgre_protocol); return 0; } diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v2.4.3/linux/net/ipv4/ip_input.c Mon Dec 11 12:37:04 2000 +++ linux/net/ipv4/ip_input.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.51 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: ip_input.c,v 1.53 2000/12/18 19:01:50 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -207,8 +207,7 @@ skb2 = skb_clone(skb, GFP_ATOMIC); if(skb2 != NULL) { ret = 1; - ipprot->handler(skb2, - ntohs(iph->tot_len) - (iph->ihl * 4)); + ipprot->handler(skb2); } } ipprot = (struct inet_protocol *) ipprot->next; @@ -219,18 +218,31 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; + int ihl = skb->nh.iph->ihl*4; #ifdef CONFIG_NETFILTER_DEBUG nf_debug_ip_local_deliver(skb); #endif /*CONFIG_NETFILTER_DEBUG*/ + /* Pull out additionl 8 bytes to save some space in protocols. */ + if (!pskb_may_pull(skb, ihl+8)) + goto out; + __skb_pull(skb, ihl); + +#ifdef CONFIG_NETFILTER + /* Free reference early: we don't need it any more, and it may + hold ip_conntrack module loaded indefinitely. */ + nf_conntrack_put(skb->nfct); + skb->nfct = NULL; +#endif /*CONFIG_NETFILTER*/ + /* Point into the IP datagram, just past the header. */ - skb->h.raw = skb->nh.raw + iph->ihl*4; + skb->h.raw = skb->data; { /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ - int hash = iph->protocol & (MAX_INET_PROTOS - 1); + int protocol = skb->nh.iph->protocol; + int hash = protocol & (MAX_INET_PROTOS - 1); struct sock *raw_sk = raw_v4_htable[hash]; struct inet_protocol *ipprot; int flag; @@ -239,23 +251,22 @@ * don't care less */ if(raw_sk != NULL) - raw_sk = raw_v4_input(skb, iph, hash); + raw_sk = raw_v4_input(skb, skb->nh.iph, hash); ipprot = (struct inet_protocol *) inet_protos[hash]; flag = 0; if(ipprot != NULL) { if(raw_sk == NULL && ipprot->next == NULL && - ipprot->protocol == iph->protocol) { + ipprot->protocol == protocol) { int ret; - + /* Fast path... */ - ret = ipprot->handler(skb, (ntohs(iph->tot_len) - - (iph->ihl * 4))); + ret = ipprot->handler(skb); return ret; } else { - flag = ip_run_ipprot(skb, iph, ipprot, (raw_sk != NULL)); + flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL)); } } @@ -269,6 +280,7 @@ sock_put(raw_sk); } else if (!flag) { /* Free and report errors */ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); +out: kfree_skb(skb); } } @@ -281,13 +293,11 @@ */ int ip_local_deliver(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; - /* * Reassemble IP fragments. */ - if (iph->frag_off & htons(IP_MF|IP_OFFSET)) { + if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb); if (!skb) return 0; @@ -333,9 +343,8 @@ --ANK (980813) */ - skb = skb_cow(skb, skb_headroom(skb)); - if (skb == NULL) - return NET_RX_DROP; + if (skb_cow(skb, skb_headroom(skb))) + goto drop; iph = skb->nh.iph; skb->ip_summed = 0; @@ -387,6 +396,11 @@ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto inhdr_error; + + iph = skb->nh.iph; + /* * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. * @@ -398,9 +412,13 @@ * 4. Doesn't have a bogus length */ - if (skb->len < sizeof(struct iphdr) || skb->len < (iph->ihl<<2)) + if (iph->ihl < 5 || iph->version != 4) goto inhdr_error; - if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0) + + if (!pskb_may_pull(skb, iph->ihl*4)) + goto inhdr_error; + + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) goto inhdr_error; { @@ -412,7 +430,11 @@ * is IP we can trim to the true length of the frame. * Note this now means skb->len holds ntohs(iph->tot_len). */ - __skb_trim(skb, len); + if (skb->len > len) { + __pskb_trim(skb, len); + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + } } return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c --- v2.4.3/linux/net/ipv4/ip_nat_dumb.c Fri Oct 27 11:03:14 2000 +++ linux/net/ipv4/ip_nat_dumb.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Dumb Network Address Translation. * - * Version: $Id: ip_nat_dumb.c,v 1.10 2000/10/24 22:54:26 davem Exp $ + * Version: $Id: ip_nat_dumb.c,v 1.11 2000/12/13 18:31:48 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -70,8 +70,14 @@ cksum = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check; if ((u8*)(cksum+1) > skb->tail) goto truncated; - check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum)); - *cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); + check = *cksum; + if (skb->ip_summed != CHECKSUM_HW) + check = ~check; + check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check); + check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); + if (skb->ip_summed == CHECKSUM_HW) + check = ~check; + *cksum = check; break; case IPPROTO_UDP: cksum = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check; diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.4.3/linux/net/ipv4/ip_output.c Fri Oct 27 11:03:14 2000 +++ linux/net/ipv4/ip_output.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.87 2000/10/25 20:07:22 davem Exp $ + * Version: $Id: ip_output.c,v 1.91 2001/03/29 06:25:55 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -95,7 +95,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb) { newskb->mac.raw = newskb->data; - skb_pull(newskb, newskb->nh.raw - newskb->data); + __skb_pull(newskb, newskb->nh.raw - newskb->data); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; BUG_TRAP(newskb->dst); @@ -141,7 +141,7 @@ iph->saddr = rt->rt_src; iph->protocol = sk->protocol; iph->tot_len = htons(skb->len); - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); skb->nh.iph = iph; if (opt && opt->optlen) { @@ -307,7 +307,7 @@ if (ip_dont_fragment(sk, &rt->u.dst)) iph->frag_off |= __constant_htons(IP_DF); - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); /* Add an IP checksum. */ ip_send_check(iph); @@ -328,7 +328,10 @@ kfree_skb(skb); return -EMSGSIZE; } - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); + if (skb->ip_summed == CHECKSUM_HW && + (skb = skb_checksum_help(skb)) == NULL) + return -ENOMEM; return ip_fragment(skb, skb->dst->output); } @@ -358,6 +361,7 @@ sk->bound_dev_if)) goto no_route; __sk_dst_set(sk, &rt->u.dst); + sk->route_caps = rt->u.dst.dev->features; } skb->dst = dst_clone(&rt->u.dst); @@ -425,7 +429,7 @@ int err; int offset, mf; int mtu; - u16 id = 0; + u16 id; int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; int nfrags=0; @@ -495,6 +499,8 @@ * Begin outputting the bytes. */ + id = (sk ? sk->protinfo.af_inet.id++ : 0); + do { char *data; struct sk_buff * skb; @@ -503,7 +509,7 @@ * Get the memory we require with some space left for alignment. */ - skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, 0, flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, flags&MSG_DONTWAIT, &err); if (skb == NULL) goto error; @@ -659,7 +665,7 @@ int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; skb = sock_alloc_send_skb(sk, length+hh_len+15, - 0, flags&MSG_DONTWAIT, &err); + flags&MSG_DONTWAIT, &err); if(skb==NULL) goto error; skb_reserve(skb, hh_len); @@ -677,7 +683,7 @@ iph->tot_len = htons(length); iph->frag_off = df; iph->ttl=sk->protinfo.af_inet.mc_ttl; - ip_select_ident(iph, &rt->u.dst); + ip_select_ident(iph, &rt->u.dst, sk); if (rt->rt_type != RTN_MULTICAST) iph->ttl=sk->protinfo.af_inet.ttl; iph->protocol=sk->protocol; @@ -722,8 +728,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct iphdr *iph; - unsigned char *raw; - unsigned char *ptr; + int raw = 0; + int ptr; struct net_device *dev; struct sk_buff *skb2; unsigned int mtu, hlen, left, len; @@ -738,17 +744,16 @@ * Point into the IP datagram header. */ - raw = skb->nh.raw; - iph = (struct iphdr*)raw; + iph = skb->nh.iph; /* * Setup starting values. */ hlen = iph->ihl * 4; - left = ntohs(iph->tot_len) - hlen; /* Space per frame */ + left = skb->len - hlen; /* Space per frame */ mtu = rt->u.dst.pmtu - hlen; /* Size of data space */ - ptr = raw + hlen; /* Where to start from */ + ptr = raw + hlen; /* Where to start from */ /* * Fragment the datagram. @@ -806,12 +811,13 @@ * Copy the packet header into the new buffer. */ - memcpy(skb2->nh.raw, raw, hlen); + memcpy(skb2->nh.raw, skb->data, hlen); /* * Copy a block of the IP datagram. */ - memcpy(skb2->h.raw, ptr, len); + if (skb_copy_bits(skb, ptr, skb2->h.raw, len)) + BUG(); left -= len; /* @@ -828,6 +834,9 @@ */ if (offset == 0) ip_options_fragment(skb); + + /* Copy the flags to each fragment. */ + IPCB(skb2)->flags = IPCB(skb)->flags; /* * Added AC : If we are fragmenting a fragment that's not the diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.4.3/linux/net/ipv4/ip_sockglue.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv4/ip_sockglue.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.54 2000/11/28 13:34:56 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.56 2001/02/18 09:07:58 davem Exp $ * * Authors: see ip.c * @@ -257,9 +257,8 @@ serr->port = port; skb->h.raw = payload; - skb_pull(skb, payload - skb->data); - - if (sock_queue_err_skb(sk, skb)) + if (!skb_pull(skb, payload - skb->data) || + sock_queue_err_skb(sk, skb)) kfree_skb(skb); } @@ -292,7 +291,7 @@ serr->port = port; skb->h.raw = skb->tail; - skb_pull(skb, skb->tail - skb->data); + __skb_pull(skb, skb->tail - skb->data); if (sock_queue_err_skb(sk, skb)) kfree_skb(skb); @@ -323,7 +322,7 @@ msg->msg_flags |= MSG_TRUNC; copied = len; } - err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto out_free_skb; @@ -333,9 +332,10 @@ sin = (struct sockaddr_in *)msg->msg_name; if (sin) { - sin->sin_family = AF_INET; + sin->sin_family = AF_INET; sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); - sin->sin_port = serr->port; + sin->sin_port = serr->port; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); @@ -344,6 +344,8 @@ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = skb->nh.iph->saddr; + sin->sin_port = 0; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); } @@ -661,7 +663,9 @@ if(get_user(len,optlen)) return -EFAULT; - + if(len < 0) + return -EINVAL; + lock_sock(sk); switch(optname) { diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c --- v2.4.3/linux/net/ipv4/ipip.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv4/ipip.c Thu Apr 12 12:11:39 2001 @@ -1,7 +1,7 @@ /* * Linux NET3: IP/IP protocol decoder. * - * Version: $Id: ipip.c,v 1.41 2000/11/28 13:13:27 davem Exp $ + * Version: $Id: ipip.c,v 1.44 2001/03/29 06:29:09 davem Exp $ * * Authors: * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 @@ -123,11 +123,13 @@ static int ipip_tunnel_init(struct net_device *dev); static struct net_device ipip_fb_tunnel_dev = { - "tunl0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip_fb_tunnel_init, + name: "tunl0", + init: ipip_fb_tunnel_init, }; static struct ip_tunnel ipip_fb_tunnel = { - NULL, &ipip_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"tunl0", } + dev: &ipip_fb_tunnel_dev, + parms: { name: "tunl0", } }; static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; @@ -281,14 +283,12 @@ write_lock_bh(&ipip_lock); tunnels_wc[0] = NULL; write_unlock_bh(&ipip_lock); - dev_put(dev); - } else { + } else ipip_tunnel_unlink((struct ip_tunnel*)dev->priv); - dev_put(dev); - } + dev_put(dev); } -void ipip_err(struct sk_buff *skb, unsigned char *dp, int len) +void ipip_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -296,14 +296,11 @@ 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)dp; + struct iphdr *iph = (struct iphdr*)skb->data; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - if (len < sizeof(struct iphdr)) - return; - switch (type) { default: case ICMP_PARAMETERPROB: @@ -473,17 +470,19 @@ IP_ECN_set_ce(iph); } -int ipip_rcv(struct sk_buff *skb, unsigned short len) +int ipip_rcv(struct sk_buff *skb) { struct iphdr *iph; struct ip_tunnel *tunnel; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + iph = skb->nh.iph; skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data); + skb->nh.raw = skb->data; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = __constant_htons(ETH_P_IP); - skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; read_lock(&ipip_lock); @@ -508,6 +507,7 @@ read_unlock(&ipip_lock); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); +out: kfree_skb(skb); return 0; } @@ -873,44 +873,34 @@ } static struct inet_protocol ipip_protocol = { - ipip_rcv, /* IPIP handler */ - ipip_err, /* TUNNEL error control */ - 0, /* next */ - IPPROTO_IPIP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "IPIP" /* name */ + handler: ipip_rcv, + err_handler: ipip_err, + protocol: IPPROTO_IPIP, + name: "IPIP" }; -#ifdef MODULE -int init_module(void) -#else +static const char banner[] __initdata = + KERN_INFO "IPv4 over IPv4 tunneling driver\n"; + int __init ipip_init(void) -#endif { - printk(KERN_INFO "IPv4 over IPv4 tunneling driver\n"); + printk(banner); ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel; -#ifdef MODULE register_netdev(&ipip_fb_tunnel_dev); -#else - rtnl_lock(); - register_netdevice(&ipip_fb_tunnel_dev); - rtnl_unlock(); -#endif - inet_add_protocol(&ipip_protocol); return 0; } -#ifdef MODULE - -void cleanup_module(void) +static void __exit ipip_fini(void) { if ( inet_del_protocol(&ipip_protocol) < 0 ) printk(KERN_INFO "ipip close: can't remove protocol\n"); - unregister_netdevice(&ipip_fb_tunnel_dev); + unregister_netdev(&ipip_fb_tunnel_dev); } +#ifdef MODULE +module_init(ipip_init); #endif +module_exit(ipip_fini); diff -u --recursive --new-file v2.4.3/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.4.3/linux/net/ipv4/ipmr.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv4/ipmr.c Thu Apr 12 12:11:39 2001 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: ipmr.c,v 1.55 2000/11/28 13:13:27 davem Exp $ + * Version: $Id: ipmr.c,v 1.59 2001/02/23 06:32:11 davem Exp $ * * Fixes: * Michael Chastain : Incorrect size of copying. @@ -980,6 +980,9 @@ return -EFAULT; olr=min(olr,sizeof(int)); + if(olr<0) + return -EINVAL; + if(put_user(olr,optlen)) return -EFAULT; if(optname==MRT_VERSION) @@ -1092,7 +1095,7 @@ iph->protocol = IPPROTO_IPIP; iph->ihl = 5; iph->tot_len = htons(skb->len); - ip_select_ident(iph, skb->dst); + ip_select_ident(iph, skb->dst, NULL); ip_send_check(iph); skb->h.ipiph = skb->nh.iph; @@ -1383,14 +1386,22 @@ * Handle IGMP messages of PIMv1 */ -int pim_rcv_v1(struct sk_buff * skb, unsigned short len) +int pim_rcv_v1(struct sk_buff * skb) { struct igmphdr *pim = (struct igmphdr*)skb->h.raw; struct iphdr *encap; struct net_device *reg_dev = NULL; + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + pim = (struct igmphdr*)skb->h.raw; + } + if (!mroute_do_pim || - len < sizeof(*pim) + sizeof(*encap) || + skb->len < sizeof(*pim) + sizeof(*encap) || pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) { kfree_skb(skb); return -EINVAL; @@ -1405,7 +1416,7 @@ */ if (!MULTICAST(encap->daddr) || ntohs(encap->tot_len) == 0 || - ntohs(encap->tot_len) + sizeof(*pim) > len) { + ntohs(encap->tot_len) + sizeof(*pim) > skb->len) { kfree_skb(skb); return -EINVAL; } @@ -1445,17 +1456,25 @@ #endif #ifdef CONFIG_IP_PIMSM_V2 -int pim_rcv(struct sk_buff * skb, unsigned short len) +int pim_rcv(struct sk_buff * skb) { struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw; struct iphdr *encap; struct net_device *reg_dev = NULL; - if (len < sizeof(*pim) + sizeof(*encap) || + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return -ENOMEM; + } + pim = (struct pimreghdr*)skb->h.raw; + } + + if (skb->len < sizeof(*pim) + sizeof(*encap) || pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && - ip_compute_csum((void *)pim, len))) { + ip_compute_csum((void *)pim, skb->len))) { kfree_skb(skb); return -EINVAL; } @@ -1464,7 +1483,7 @@ encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr)); if (!MULTICAST(encap->daddr) || ntohs(encap->tot_len) == 0 || - ntohs(encap->tot_len) + sizeof(*pim) > len) { + ntohs(encap->tot_len) + sizeof(*pim) > skb->len) { kfree_skb(skb); return -EINVAL; } diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c --- v2.4.3/linux/net/ipv4/netfilter/ip_conntrack_core.c Mon Jan 22 13:30:21 2001 +++ linux/net/ipv4/netfilter/ip_conntrack_core.c Thu Apr 12 12:11:39 2001 @@ -894,7 +894,12 @@ if (!skb) { if (sk) sock_put(sk); return skb; + } else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + if (sk) sock_put(sk); + return NULL; } + if (sk) { skb_set_owner_w(skb, sk); sock_put(sk); @@ -986,7 +991,7 @@ return -ENOPROTOOPT; } - if (*len != sizeof(struct sockaddr_in)) { + if ((unsigned int) *len < sizeof(struct sockaddr_in)) { DEBUGP("SO_ORIGINAL_DST: len %u not %u\n", *len, sizeof(struct sockaddr_in)); return -EINVAL; diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c --- v2.4.3/linux/net/ipv4/netfilter/ip_fw_compat.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/netfilter/ip_fw_compat.c Thu Apr 12 12:11:39 2001 @@ -96,7 +96,8 @@ /* Assume worse case: any hook could change packet */ (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; - (*pskb)->ip_summed = CHECKSUM_NONE; + if ((*pskb)->ip_summed == CHECKSUM_HW) + (*pskb)->ip_summed = CHECKSUM_NONE; switch (hooknum) { case NF_IP_PRE_ROUTING: diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c --- v2.4.3/linux/net/ipv4/netfilter/ip_nat_standalone.c Sat Feb 3 11:45:55 2001 +++ linux/net/ipv4/netfilter/ip_nat_standalone.c Thu Apr 12 12:11:39 2001 @@ -64,7 +64,7 @@ (*pskb)->nfcache |= NFC_UNKNOWN; /* If we had a hardware checksum before, it's now invalid */ - if ((*pskb)->pkt_type != PACKET_LOOPBACK) + if ((*pskb)->ip_summed == CHECKSUM_HW) (*pskb)->ip_summed = CHECKSUM_NONE; ct = ip_conntrack_get(*pskb, &ctinfo); diff -u --recursive --new-file v2.4.3/linux/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c --- v2.4.3/linux/net/ipv4/netfilter/ipchains_core.c Thu Apr 13 17:19:57 2000 +++ linux/net/ipv4/netfilter/ipchains_core.c Thu Apr 12 12:11:39 2001 @@ -871,7 +871,7 @@ if (chainptr->chain == NULL) { /* If pointer writes are atomic then turning off - * interupts is not necessary. */ + * interrupts is not necessary. */ chainptr->chain = rule; if (rule->branch) rule->branch->refcount++; return 0; diff -u --recursive --new-file v2.4.3/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.4.3/linux/net/ipv4/raw.c Fri Feb 9 11:29:44 2001 +++ linux/net/ipv4/raw.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.56 2000/11/28 13:38:38 davem Exp $ + * Version: $Id: raw.c,v 1.60 2001/02/23 06:32:11 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -170,11 +170,10 @@ return sk; } -void raw_err (struct sock *sk, struct sk_buff *skb) +void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) { int type = skb->h.icmph->type; int code = skb->h.icmph->code; - u32 info = 0; int err = 0; int harderr = 0; @@ -195,7 +194,6 @@ return; case ICMP_PARAMETERPROB: err = EPROTO; - info = ntohl(skb->h.icmph->un.gateway)>>24; harderr = 1; break; case ICMP_DEST_UNREACH: @@ -207,12 +205,17 @@ if (code == ICMP_FRAG_NEEDED) { harderr = (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT); err = EMSGSIZE; - info = ntohs(skb->h.icmph->un.frag.mtu); } } - if (sk->protinfo.af_inet.recverr) - ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1)); + if (sk->protinfo.af_inet.recverr) { + struct iphdr *iph = (struct iphdr*)skb->data; + u8 *payload = skb->data+(iph->ihl<<2); + + if (sk->protinfo.af_inet.hdrincl) + payload = skb->data; + ip_icmp_error(sk, skb, err, 0, info, payload); + } if (sk->protinfo.af_inet.recverr || harderr) { sk->err = err; @@ -235,18 +238,9 @@ return NET_RX_SUCCESS; } -/* - * This should be the easiest of all, all we do is - * copy it into a buffer. All demultiplexing is done - * in ip.c - */ - int raw_rcv(struct sock *sk, struct sk_buff *skb) { - /* Now we need to copy this into memory. */ - skb_trim(skb, ntohs(skb->nh.iph->tot_len)); - - skb->h.raw = skb->nh.raw; + skb_push(skb, skb->data-skb->nh.raw); raw_rcv_skb(sk, skb); return 0; @@ -296,7 +290,7 @@ * ip_build_xmit clean (well less messy). */ if (!iph->id) - ip_select_ident(iph, rfh->dst); + ip_select_ident(iph, rfh->dst, NULL); iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl); } return 0; @@ -498,7 +492,7 @@ msg->msg_flags |= MSG_TRUNC; copied = len; } - + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto done; @@ -540,6 +534,8 @@ if (get_user(len,optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; if (len > sizeof(struct icmp_filter)) len = sizeof(struct icmp_filter); if (put_user(len, optlen)) diff -u --recursive --new-file v2.4.3/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.4.3/linux/net/ipv4/route.c Tue Oct 10 10:33:52 2000 +++ linux/net/ipv4/route.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.91 2000/10/03 07:29:00 anton Exp $ + * Version: $Id: route.c,v 1.93 2001/02/22 01:03:05 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -115,7 +115,7 @@ int ip_rt_gc_elasticity = 8; int ip_rt_mtu_expires = 10*60*HZ; int ip_rt_min_pmtu = 512+20+20; -int ip_rt_min_advmss = 536; +int ip_rt_min_advmss = 256; static unsigned long rt_deadline; @@ -667,7 +667,7 @@ spin_lock_bh(&ip_fb_id_lock); salt = secure_ip_id(ip_fallback_id ^ iph->daddr); - iph->id = salt & 0xFFFF; + iph->id = htons(salt & 0xFFFF); ip_fallback_id = salt; spin_unlock_bh(&ip_fb_id_lock); } @@ -684,7 +684,7 @@ so that we need not to grab a lock to dereference it. */ if (rt->peer) { - iph->id = inet_getid(rt->peer); + iph->id = htons(inet_getid(rt->peer)); return; } } else { diff -u --recursive --new-file v2.4.3/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c --- v2.4.3/linux/net/ipv4/syncookies.c Fri Feb 9 11:29:44 2001 +++ linux/net/ipv4/syncookies.c Thu Apr 12 12:11:39 2001 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: syncookies.c,v 1.12 2000/07/26 01:04:19 davem Exp $ + * $Id: syncookies.c,v 1.13 2001/02/13 01:17:26 davem Exp $ * * Missing: IPv6 support. */ diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.4.3/linux/net/ipv4/tcp.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/tcp.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.180 2000/11/28 17:04:09 davem Exp $ + * Version: $Id: tcp.c,v 1.201 2001/03/06 22:42:56 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -520,6 +520,7 @@ sk->ack_backlog = 0; tp->accept_queue = tp->accept_queue_tail = NULL; tp->syn_wait_lock = RW_LOCK_UNLOCKED; + tcp_delack_init(tp); lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL); if (!lopt) @@ -642,11 +643,8 @@ if(sk->err) return sock_error(sk); if((1 << sk->state) & - ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) { - if(sk->keepopen && !(flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE, tsk, 0); + ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) return -EPIPE; - } if(!*timeo_p) return -EAGAIN; if(signal_pending(tsk)) @@ -675,56 +673,326 @@ /* * Wait for more memory for a socket */ -static long wait_for_tcp_memory(struct sock * sk, long timeo) +static int wait_for_tcp_memory(struct sock * sk, long *timeo) { + int err = 0; long vm_wait = 0; - long current_timeo = timeo; + long current_timeo = *timeo; DECLARE_WAITQUEUE(wait, current); if (tcp_memory_free(sk)) current_timeo = vm_wait = (net_random()%(HZ/5))+2; - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - add_wait_queue(sk->sleep, &wait); for (;;) { - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); set_current_state(TASK_INTERRUPTIBLE); + if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + goto do_error; + if (!*timeo) + goto do_nonblock; if (signal_pending(current)) - break; + goto do_interrupted; + clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); if (tcp_memory_free(sk) && !vm_wait) break; - if (sk->shutdown & SEND_SHUTDOWN) - break; - if (sk->err) - break; + + set_bit(SOCK_NOSPACE, &sk->socket->flags); + sk->tp_pinfo.af_tcp.write_pending++; release_sock(sk); if (!tcp_memory_free(sk) || vm_wait) current_timeo = schedule_timeout(current_timeo); lock_sock(sk); + sk->tp_pinfo.af_tcp.write_pending--; + if (vm_wait) { - if (timeo != MAX_SCHEDULE_TIMEOUT && - (timeo -= vm_wait-current_timeo) < 0) - timeo = 0; - break; - } else { - timeo = current_timeo; + vm_wait -= current_timeo; + current_timeo = *timeo; + if (current_timeo != MAX_SCHEDULE_TIMEOUT && + (current_timeo -= vm_wait) < 0) + current_timeo = 0; + vm_wait = 0; } + *timeo = current_timeo; } +out: current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); - return timeo; + return err; + +do_error: + err = -EPIPE; + goto out; +do_nonblock: + err = -EAGAIN; + goto out; +do_interrupted: + err = sock_intr_errno(*timeo); + goto out; } -/* When all user supplied data has been queued set the PSH bit */ -#define PSH_NEEDED (seglen == 0 && iovlen == 0) +ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags); -/* - * This routine copies from a user buffer into a socket, - * and starts the transmit system. - */ +static inline int +can_coalesce(struct sk_buff *skb, int i, struct page *page, int off) +{ + if (i) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; + return page == frag->page && + off == frag->page_offset+frag->size; + } + return 0; +} + +static inline void +fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) +{ + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + frag->page = page; + frag->page_offset = off; + frag->size = size; + skb_shinfo(skb)->nr_frags = i+1; +} + +static inline void tcp_mark_push(struct tcp_opt *tp, struct sk_buff *skb) +{ + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; + tp->pushed_seq = tp->write_seq; +} + +static inline int forced_push(struct tcp_opt *tp) +{ + return after(tp->write_seq, tp->pushed_seq + (tp->max_window>>1)); +} + +static inline void +skb_entail(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) +{ + skb->csum = 0; + TCP_SKB_CB(skb)->seq = tp->write_seq; + TCP_SKB_CB(skb)->end_seq = tp->write_seq; + TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; + TCP_SKB_CB(skb)->sacked = 0; + __skb_queue_tail(&sk->write_queue, skb); + tcp_charge_skb(sk, skb); + if (tp->send_head == NULL) + tp->send_head = skb; +} + +static inline void +tcp_mark_urg(struct tcp_opt *tp, int flags, struct sk_buff *skb) +{ + if (flags & MSG_OOB) { + tp->urg_mode = 1; + tp->snd_up = tp->write_seq; + TCP_SKB_CB(skb)->sacked |= TCPCB_URG; + } +} + +static inline void +tcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle) +{ + if (tp->send_head) { + struct sk_buff *skb = sk->write_queue.prev; + if (!(flags&MSG_MORE) || forced_push(tp)) + tcp_mark_push(tp, skb); + tcp_mark_urg(tp, flags, skb); + __tcp_push_pending_frames(sk, tp, mss_now, (flags&MSG_MORE) ? 2 : nonagle); + } +} + +static int tcp_error(struct sock *sk, int flags, int err) +{ + if (err == -EPIPE) + err = sock_error(sk) ? : -EPIPE; + if (err == -EPIPE && !(flags&MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); + return err; +} + +ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int mss_now; + int err; + ssize_t copied; + long timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT); + + /* Wait for a connection to finish. */ + if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) + if((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0) + goto out_err; + + clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + + mss_now = tcp_current_mss(sk); + copied = 0; + + err = -EPIPE; + if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + goto do_error; + + while (psize > 0) { + struct sk_buff *skb = sk->write_queue.prev; + int offset, size, copy, i; + struct page *page; + + page = pages[poffset/PAGE_SIZE]; + offset = poffset % PAGE_SIZE; + size = min(psize, PAGE_SIZE-offset); + + if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) { +new_segment: + if (!tcp_memory_free(sk)) + goto wait_for_sndbuf; + + skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, sk->allocation); + if (skb == NULL) + goto wait_for_memory; + + skb_entail(sk, tp, skb); + copy = mss_now; + } + + if (copy > size) + copy = size; + + i = skb_shinfo(skb)->nr_frags; + if (can_coalesce(skb, i, page, offset)) { + skb_shinfo(skb)->frags[i-1].size += copy; + } else if (i < MAX_SKB_FRAGS) { + get_page(page); + fill_page_desc(skb, i, page, offset, copy); + } else { + tcp_mark_push(tp, skb); + goto new_segment; + } + + skb->len += copy; + skb->data_len += copy; + skb->ip_summed = CHECKSUM_HW; + tp->write_seq += copy; + TCP_SKB_CB(skb)->end_seq += copy; + + if (!copied) + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; + + copied += copy; + poffset += copy; + if (!(psize -= copy)) + goto out; + + if (skb->len != mss_now || (flags&MSG_OOB)) + continue; + + if (forced_push(tp)) { + tcp_mark_push(tp, skb); + __tcp_push_pending_frames(sk, tp, mss_now, 1); + } else if (skb == tp->send_head) + tcp_push_one(sk, mss_now); + continue; + +wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->socket->flags); +wait_for_memory: + if (copied) + tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1); + + if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) + goto do_error; + + mss_now = tcp_current_mss(sk); + } + +out: + if (copied) + tcp_push(sk, tp, flags, mss_now, tp->nonagle); + return copied; + +do_error: + if (copied) + goto out; +out_err: + return tcp_error(sk, flags, err); +} + +ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) +{ + ssize_t res; + struct sock *sk = sock->sk; + +#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) + + if (!(sk->route_caps & NETIF_F_SG) || + !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) + return sock_no_sendpage(sock, page, offset, size, flags); + +#undef TCP_ZC_CSUM_FLAGS + + lock_sock(sk); + TCP_CHECK_TIMER(sk); + res = do_tcp_sendpages(sk, &page, offset, size, flags); + TCP_CHECK_TIMER(sk); + release_sock(sk); + return res; +} + +#define TCP_PAGE(sk) (sk->tp_pinfo.af_tcp.sndmsg_page) +#define TCP_OFF(sk) (sk->tp_pinfo.af_tcp.sndmsg_off) + +static inline int +tcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb, + struct page *page, int off, int copy) +{ + int err = 0; + unsigned int csum; + + csum = csum_and_copy_from_user(from, page_address(page)+off, + copy, 0, &err); + if (!err) { + if (skb->ip_summed == CHECKSUM_NONE) + skb->csum = csum_block_add(skb->csum, csum, skb->len); + skb->len += copy; + skb->data_len += copy; + skb->truesize += copy; + sk->wmem_queued += copy; + sk->forward_alloc -= copy; + } + return err; +} + +static inline int +skb_add_data(struct sk_buff *skb, char *from, int copy) +{ + int err = 0; + unsigned int csum; + int off = skb->len; + + csum = csum_and_copy_from_user(from, skb_put(skb, copy), + copy, 0, &err); + if (!err) { + skb->csum = csum_block_add(skb->csum, csum, off); + return 0; + } + + __skb_trim(skb, off); + return -EFAULT; +} + +static inline int select_size(struct sock *sk, struct tcp_opt *tp) +{ + int tmp = tp->mss_cache; + + if (sk->route_caps&NETIF_F_SG) { + int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); + + if (tmp >= pgbreak && tmp <= pgbreak + (MAX_SKB_FRAGS-1)*PAGE_SIZE) + tmp = pgbreak; + } + return tmp; +} int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size) { @@ -736,20 +1004,18 @@ int err, copied; long timeo; - err = 0; tp = &(sk->tp_pinfo.af_tcp); lock_sock(sk); TCP_CHECK_TIMER(sk); flags = msg->msg_flags; - timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT); /* Wait for a connection to finish. */ if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) if((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0) - goto out_unlock; + goto out_err; /* This should be in poll */ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); @@ -761,6 +1027,10 @@ iov = msg->msg_iov; copied = 0; + err = -EPIPE; + if (sk->err || (sk->shutdown&SEND_SHUTDOWN)) + goto do_error; + while (--iovlen >= 0) { int seglen=iov->iov_len; unsigned char * from=iov->iov_base; @@ -768,200 +1038,159 @@ iov++; while (seglen > 0) { - int copy, tmp, queue_it; - - if (err) - goto do_fault2; - - /* Stop on errors. */ - if (sk->err) - goto do_sock_err; - - /* Make sure that we are established. */ - if (sk->shutdown & SEND_SHUTDOWN) - goto do_shutdown; - - /* Now we need to check if we have a half - * built packet we can tack some data onto. - */ + int copy; + skb = sk->write_queue.prev; - if (tp->send_head && - (mss_now > skb->len)) { - copy = skb->len; - if (skb_tailroom(skb) > 0) { - int last_byte_was_odd = (copy % 4); - - copy = mss_now - copy; - if(copy > skb_tailroom(skb)) - copy = skb_tailroom(skb); - if(copy > seglen) - copy = seglen; - if(last_byte_was_odd) { - if(copy_from_user(skb_put(skb, copy), - from, copy)) - err = -EFAULT; - skb->csum = csum_partial(skb->data, - skb->len, 0); - } else { - skb->csum = - csum_and_copy_from_user( - from, skb_put(skb, copy), - copy, skb->csum, &err); - } - /* - * FIXME: the *_user functions should - * return how much data was - * copied before the fault - * occurred and then a partial - * packet with this data should - * be sent. Unfortunately - * csum_and_copy_from_user doesn't - * return this information. - * ATM it might send partly zeroed - * data in this case. - */ - tp->write_seq += copy; - TCP_SKB_CB(skb)->end_seq += copy; - from += copy; - copied += copy; - seglen -= copy; - if (PSH_NEEDED || - after(tp->write_seq, tp->pushed_seq+(tp->max_window>>1))) { - TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; - tp->pushed_seq = tp->write_seq; - } - if (flags&MSG_OOB) { - tp->urg_mode = 1; - tp->snd_up = tp->write_seq; - TCP_SKB_CB(skb)->sacked |= TCPCB_URG; - } - continue; - } else { - TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; - tp->pushed_seq = tp->write_seq; - } - } - copy = min(seglen, mss_now); + if (tp->send_head == NULL || + (copy = mss_now - skb->len) <= 0) { - /* Determine how large of a buffer to allocate. */ - tmp = MAX_TCP_HEADER + 15 + tp->mss_cache; - if (copy < mss_now && !(flags & MSG_OOB)) { - /* What is happening here is that we want to - * tack on later members of the users iovec - * if possible into a single frame. When we - * leave this loop our we check to see if - * we can send queued frames onto the wire. +new_segment: + /* Allocate new segment. If the interface is SG, + * allocate skb fitting to single page. */ - queue_it = 1; - } else { - queue_it = 0; - } - - skb = NULL; - if (tcp_memory_free(sk)) - skb = tcp_alloc_skb(sk, tmp, sk->allocation); - if (skb == NULL) { - /* If we didn't get any memory, we need to sleep. */ - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - set_bit(SOCK_NOSPACE, &sk->socket->flags); + if (!tcp_memory_free(sk)) + goto wait_for_sndbuf; - __tcp_push_pending_frames(sk, tp, mss_now, 1); - - if (!timeo) { - err = -EAGAIN; - goto do_interrupted; + skb = tcp_alloc_pskb(sk, select_size(sk, tp), 0, sk->allocation); + if (skb == NULL) + goto wait_for_memory; + + skb_entail(sk, tp, skb); + copy = mss_now; + } + + /* Try to append data to the end of skb. */ + if (copy > seglen) + copy = seglen; + + /* Where to copy to? */ + if (skb_tailroom(skb) > 0) { + /* We have some space in skb head. Superb! */ + if (copy > skb_tailroom(skb)) + copy = skb_tailroom(skb); + if ((err = skb_add_data(skb, from, copy)) != 0) + goto do_fault; + } else { + int merge = 0; + int i = skb_shinfo(skb)->nr_frags; + struct page *page = TCP_PAGE(sk); + int off = TCP_OFF(sk); + + if (can_coalesce(skb, i, page, off) && off != PAGE_SIZE) { + /* We can extend the last page fragment. */ + merge = 1; + } else if (i == MAX_SKB_FRAGS || + (i == 0 && !(sk->route_caps&NETIF_F_SG))) { + /* Need to add new fragment and cannot + * do this because interface is non-SG, + * or because all the page slots are busy. + */ + tcp_mark_push(tp, skb); + goto new_segment; + } else if (page) { + /* If page is cached, align + * offset to L1 cache boundary + */ + off = (off+L1_CACHE_BYTES-1)&~(L1_CACHE_BYTES-1); + if (off == PAGE_SIZE) { + put_page(page); + TCP_PAGE(sk) = page = NULL; + } } - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - goto do_interrupted; + + if (!page) { + /* Allocate new cache page. */ + if (!(page=tcp_alloc_page(sk))) + goto wait_for_memory; + off = 0; } - timeo = wait_for_tcp_memory(sk, timeo); - /* If SACK's were formed or PMTU events happened, - * we must find out about it. - */ - mss_now = tcp_current_mss(sk); - continue; - } + if (copy > PAGE_SIZE-off) + copy = PAGE_SIZE-off; - seglen -= copy; + /* Time to copy data. We are close to the end! */ + err = tcp_copy_to_page(sk, from, skb, page, off, copy); + if (err) + goto do_error; + + /* Update the skb. */ + if (merge) { + skb_shinfo(skb)->frags[i-1].size += copy; + } else { + fill_page_desc(skb, i, page, off, copy); + if (TCP_PAGE(sk)) { + get_page(page); + } else if (off + copy < PAGE_SIZE) { + get_page(page); + TCP_PAGE(sk) = page; + } + } - /* Prepare control bits for TCP header creation engine. */ - if (PSH_NEEDED || - after(tp->write_seq+copy, tp->pushed_seq+(tp->max_window>>1))) { - TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK|TCPCB_FLAG_PSH; - tp->pushed_seq = tp->write_seq + copy; - } else { - TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; - } - TCP_SKB_CB(skb)->sacked = 0; - if (flags & MSG_OOB) { - TCP_SKB_CB(skb)->sacked |= TCPCB_URG; - tp->urg_mode = 1; - tp->snd_up = tp->write_seq + copy; + TCP_OFF(sk) = off+copy; } - /* TCP data bytes are SKB_PUT() on top, later - * TCP+IP+DEV headers are SKB_PUSH()'d beneath. - * Reserve header space and checksum the data. - */ - skb_reserve(skb, MAX_TCP_HEADER); - skb->csum = csum_and_copy_from_user(from, - skb_put(skb, copy), copy, 0, &err); + if (!copied) + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; - if (err) - goto do_fault; + tp->write_seq += copy; + TCP_SKB_CB(skb)->end_seq += copy; from += copy; copied += copy; + seglen -= copy; + + if (skb->len != mss_now || (flags&MSG_OOB)) + continue; - TCP_SKB_CB(skb)->seq = tp->write_seq; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + copy; + if (forced_push(tp)) { + tcp_mark_push(tp, skb); + __tcp_push_pending_frames(sk, tp, mss_now, 1); + } else if (skb == tp->send_head) + tcp_push_one(sk, mss_now); + continue; - /* This advances tp->write_seq for us. */ - tcp_send_skb(sk, skb, queue_it, mss_now); +wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->socket->flags); +wait_for_memory: + if (copied) + tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1); + + if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) + goto do_error; + + mss_now = tcp_current_mss(sk); } } - err = copied; + out: - __tcp_push_pending_frames(sk, tp, mss_now, tp->nonagle); -out_unlock: + if (copied) + tcp_push(sk, tp, flags, mss_now, tp->nonagle); TCP_CHECK_TIMER(sk); release_sock(sk); - return err; + return copied; -do_sock_err: - if (copied) - err = copied; - else - err = sock_error(sk); - goto out; -do_shutdown: - if (copied) - err = copied; - else { - if (!(flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - err = -EPIPE; - } - goto out; -do_interrupted: - if (copied) - err = copied; - goto out_unlock; do_fault: - __kfree_skb(skb); -do_fault2: + if (skb->len==0) { + if (tp->send_head == skb) { + tp->send_head = skb->prev; + if (tp->send_head == (struct sk_buff*)&sk->write_queue) + tp->send_head = NULL; + } + __skb_unlink(skb, skb->list); + tcp_free_skb(sk, skb); + } + +do_error: if (copied) - err = copied; - else - err = -EFAULT; - goto out; + goto out; +out_err: + err = tcp_error(sk, flags, err); + TCP_CHECK_TIMER(sk); + release_sock(sk); + return err; } -#undef PSH_NEEDED - /* * Handle reading urgent data. BSD has very simple semantics for * this, no blocking and very strange errors 8) @@ -991,7 +1220,7 @@ msg->msg_flags|=MSG_OOB; if(len>0) { - if (!(flags & MSG_PEEK)) + if (!(flags & MSG_PEEK) && !(flags & MSG_TRUNC)) err = memcpy_toiovec(msg->msg_iov, &c, 1); len = 1; } else @@ -1033,17 +1262,13 @@ static void cleanup_rbuf(struct sock *sk, int copied) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct sk_buff *skb; int time_to_ack = 0; - /* NOTE! The socket must be locked, so that we don't get - * a messed-up receive queue. - */ - while ((skb=skb_peek(&sk->receive_queue)) != NULL) { - if (!skb->used) - break; - tcp_eat_skb(sk, skb); - } +#if TCP_DEBUG + struct sk_buff *skb = skb_peek(&sk->receive_queue); + + BUG_TRAP(skb==NULL || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)); +#endif if (tcp_ack_scheduled(tp)) { /* Delayed ACKs frequently hit locked sockets during bulk receive. */ @@ -1219,8 +1444,7 @@ goto found_ok_skb; if (skb->h.th->fin) goto found_fin_ok; - if (!(flags & MSG_PEEK)) - skb->used = 1; + BUG_TRAP(flags&MSG_PEEK); skb = skb->next; } while (skb != (struct sk_buff *)&sk->receive_queue); @@ -1233,7 +1457,8 @@ if (sk->err || sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN) || - !timeo) + !timeo || + (flags & MSG_PEEK)) break; } else { if (sk->done) @@ -1358,15 +1583,16 @@ ++*seq; offset++; used--; + if (!used) + goto skip_copy; } } else used = urg_offset; } } - err = 0; if (!(flags&MSG_TRUNC)) { - err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used); + err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used); if (err) { /* Exception. Bailout! */ if (!copied) @@ -1379,37 +1605,25 @@ copied += used; len -= used; - if (after(tp->copied_seq,tp->urg_seq)) { +skip_copy: + if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) { tp->urg_data = 0; - if (skb_queue_len(&tp->out_of_order_queue) == 0 -#ifdef TCP_FORMAL_WINDOW - && tcp_receive_window(tp) -#endif - ) { - tcp_fast_path_on(tp); - } + tcp_fast_path_check(sk, tp); } if (used + offset < skb->len) continue; - /* Process the FIN. We may also need to handle PSH - * here and make it break out of MSG_WAITALL. - */ if (skb->h.th->fin) goto found_fin_ok; - if (flags & MSG_PEEK) - continue; - skb->used = 1; - tcp_eat_skb(sk, skb); + if (!(flags & MSG_PEEK)) + tcp_eat_skb(sk, skb); continue; found_fin_ok: + /* Process the FIN. */ ++*seq; - if (flags & MSG_PEEK) - break; - - /* All is done. */ - skb->used = 1; + if (!(flags & MSG_PEEK)) + tcp_eat_skb(sk, skb); break; } while (len > 0); @@ -1556,7 +1770,7 @@ /* It cannot be in hash table! */ BUG_TRAP(sk->pprev==NULL); - /* It it has not 0 sk->num, it must be bound */ + /* If it has not 0 sk->num, it must be bound */ BUG_TRAP(!sk->num || sk->prev!=NULL); #ifdef TCP_DEBUG @@ -2041,7 +2255,7 @@ tp->defer_accept = 0; if (val > 0) { /* Translate value in seconds to number of retransmits */ - while (val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept)) + while (tp->defer_accept < 32 && val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept)) tp->defer_accept++; tp->defer_accept++; } @@ -2060,6 +2274,21 @@ } break; + case TCP_QUICKACK: + if (!val) { + tp->ack.pingpong = 1; + } else { + tp->ack.pingpong = 0; + if ((1<<sk->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT) && + tcp_ack_scheduled(tp)) { + tp->ack.pending |= TCP_ACK_PUSHED; + cleanup_rbuf(sk, 1); + if (!(val & 1)) + tp->ack.pingpong = 1; + } + } + break; + default: err = -ENOPROTOOPT; break; @@ -2082,6 +2311,9 @@ return -EFAULT; len = min(len, sizeof(int)); + + if(len < 0) + return -EINVAL; switch(optname) { case TCP_MAXSEG: @@ -2180,6 +2412,9 @@ return -EFAULT; return 0; } + case TCP_QUICKACK: + val = !tp->ack.pingpong; + break; default: return -ENOPROTOOPT; }; @@ -2230,7 +2465,10 @@ * * The methodology is similar to that of the buffer cache. */ - goal = num_physpages >> (23 - PAGE_SHIFT); + if (num_physpages >= (128 * 1024)) + goal = num_physpages >> (21 - PAGE_SHIFT); + else + goal = num_physpages >> (23 - PAGE_SHIFT); for(order = 0; (1UL << order) < goal; order++) ; @@ -2284,9 +2522,9 @@ } tcp_port_rover = sysctl_local_port_range[0] - 1; - sysctl_tcp_mem[0] = 64<<order; - sysctl_tcp_mem[1] = 200<<order; - sysctl_tcp_mem[2] = 256<<order; + sysctl_tcp_mem[0] = 768<<order; + sysctl_tcp_mem[1] = 1024<<order; + sysctl_tcp_mem[2] = 1536<<order; if (sysctl_tcp_mem[2] - sysctl_tcp_mem[1] > 512) sysctl_tcp_mem[1] = sysctl_tcp_mem[2] - 512; if (sysctl_tcp_mem[1] - sysctl_tcp_mem[0] > 512) diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.4.3/linux/net/ipv4/tcp_input.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/tcp_input.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.205 2000/12/13 18:31:48 davem Exp $ + * Version: $Id: tcp_input.c,v 1.226 2001/03/07 22:00:57 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -137,7 +137,7 @@ * * "len" is invariant segment length, including TCP header. */ - len = skb->tail - skb->h.raw; + len += skb->data - skb->h.raw; if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) || /* If PSH is not set, packet should be * full sized, provided peer TCP is not badly broken. @@ -378,7 +378,8 @@ /* The _first_ data packet received, initialize * delayed ACK engine. */ - tcp_enter_quickack_mode(tp); + tcp_incr_quickack(tp); + tp->ack.ato = TCP_ATO_MIN; } else { int m = now - tp->ack.lrcvtime; @@ -510,7 +511,7 @@ } /* Save metrics learned by this TCP session. - This function is called only, when TCP finishes sucessfully + This function is called only, when TCP finishes successfully i.e. when it enters TIME-WAIT or goes from LAST-ACK to CLOSE. */ void tcp_update_metrics(struct sock *sk) @@ -1016,7 +1017,7 @@ tp->fackets_out = cnt; } } - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); tp->reordering = min(tp->reordering, sysctl_tcp_reordering); tp->ca_state = TCP_CA_Loss; @@ -1052,6 +1053,15 @@ return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out; } +static inline int tcp_skb_timedout(struct tcp_opt *tp, struct sk_buff *skb) +{ + return (tcp_time_stamp - TCP_SKB_CB(skb)->when > tp->rto); +} + +static inline int tcp_head_timedout(struct sock *sk, struct tcp_opt *tp) +{ + return tp->packets_out && tcp_skb_timedout(tp, skb_peek(&sk->write_queue)); +} /* Linux NewReno/SACK/FACK/ECN state machine. * -------------------------------------- @@ -1157,7 +1167,13 @@ if (tcp_fackets_out(tp) > tp->reordering) return 1; - /* Trick#3: It is still not OK... But will it be useful to delay + /* Trick#3 : when we use RFC2988 timer restart, fast + * retransmit can be triggered by timeout of queue head. + */ + if (tcp_head_timedout(sk, tp)) + return 1; + + /* Trick#4: It is still not OK... But will it be useful to delay * recovery more? */ if (tp->packets_out <= tp->reordering && @@ -1178,8 +1194,10 @@ */ static void tcp_check_reno_reordering(struct tcp_opt *tp, int addend) { - if (tp->sacked_out + 1 > tp->packets_out) { - tp->sacked_out = tp->packets_out ? tp->packets_out - 1 : 0; + int holes = min(max(tp->lost_out, 1), tp->packets_out); + + if (tp->sacked_out + holes > tp->packets_out) { + tp->sacked_out = tp->packets_out - holes; tcp_update_reordering(tp, tp->packets_out+addend, 0); } } @@ -1190,7 +1208,7 @@ { ++tp->sacked_out; tcp_check_reno_reordering(tp, 0); - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); } /* Account for ACK, ACKing some data in Reno Recovery phase. */ @@ -1198,17 +1216,14 @@ static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_opt *tp, int acked) { if (acked > 0) { - /* One ACK eated lost packet. Must eat! */ - BUG_TRAP(tp->lost_out == 0); - - /* The rest eat duplicate ACKs. */ + /* One ACK acked hole. The rest eat duplicate ACKs. */ if (acked-1 >= tp->sacked_out) tp->sacked_out = 0; else tp->sacked_out -= acked-1; } tcp_check_reno_reordering(tp, acked); - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); } static inline void tcp_reset_reno_sack(struct tcp_opt *tp) @@ -1234,7 +1249,7 @@ tp->lost_out++; } } - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); } /* Account newly detected lost packet(s) */ @@ -1249,6 +1264,24 @@ } else { tcp_mark_head_lost(sk, tp, 1, tp->high_seq); } + + /* New heuristics: it is possible only after we switched + * to restart timer each time when something is ACKed. + * Hence, we can detect timed out packets during fast + * retransmit without falling to slow start. + */ + if (tcp_head_timedout(sk, tp)) { + struct sk_buff *skb; + + for_retrans_queue(skb, sk, tp) { + if (tcp_skb_timedout(tp, skb) && + !(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + tp->lost_out++; + } + } + tcp_sync_left_out(tp); + } } /* CWND moderation, preventing bursts due to too big ACKs @@ -1490,7 +1523,7 @@ } /* D. Synchronize left_out to current state. */ - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); /* E. Check state exit conditions. State can be terminated * when high_seq is ACKed. */ @@ -1516,8 +1549,13 @@ case TCP_CA_Disorder: tcp_try_undo_dsack(sk, tp); - tp->undo_marker = 0; - tp->ca_state = TCP_CA_Open; + if (!tp->undo_marker || + /* For SACK case do not Open to allow to undo + * catching for all duplicate ACKs. */ + IsReno(tp) || tp->snd_una != tp->high_seq) { + tp->undo_marker = 0; + tp->ca_state = TCP_CA_Open; + } break; case TCP_CA_Recovery: @@ -1544,8 +1582,8 @@ } break; case TCP_CA_Loss: - if (flag & FLAG_ACKED) - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + if (flag&FLAG_DATA_ACKED) + tp->retransmits = 0; if (!tcp_try_undo_loss(sk, tp)) { tcp_moderate_cwnd(tp); tcp_xmit_retransmit_queue(sk); @@ -1593,7 +1631,7 @@ tp->ca_state = TCP_CA_Recovery; } - if (is_dupack) + if (is_dupack || tcp_head_timedout(sk, tp)) tcp_update_scoreboard(sk, tp); tcp_cwnd_down(tp); tcp_xmit_retransmit_queue(sk); @@ -1613,16 +1651,18 @@ * * See draft-ietf-tcplw-high-performance-00, section 3.3. * 1998/04/10 Andrey V. Savochkin <saw@msu.ru> + * + * Changed: reset backoff as soon as we see the first valid sample. + * If we do not, we get strongly overstimated rto. With timestamps + * samples are accepted even from very old segments: f.e., when rtt=1 + * increases to 8, we retransmit 5 times and after 8 seconds delayed + * answer arrives rto becomes 120 seconds! If at least one of segments + * in window is lost... Voila. --ANK (010210) */ seq_rtt = tcp_time_stamp - tp->rcv_tsecr; tcp_rtt_estimator(tp, seq_rtt); tcp_set_rto(tp); - if (tp->backoff) { - if (!tp->retransmits || !(flag & FLAG_RETRANS_DATA_ACKED)) - tp->backoff = 0; - else - tp->rto <<= tp->backoff; - } + tp->backoff = 0; tcp_bound_rto(tp); } @@ -1642,15 +1682,7 @@ tcp_rtt_estimator(tp, seq_rtt); tcp_set_rto(tp); - if (tp->backoff) { - /* To relax it? We have valid sample as soon as we are - * here. Why not to clear backoff? - */ - if (!tp->retransmits) - tp->backoff = 0; - else - tp->rto <<= tp->backoff; - } + tp->backoff = 0; tcp_bound_rto(tp); } @@ -1684,15 +1716,11 @@ } else tp->snd_cwnd_cnt++; } + tp->snd_cwnd_stamp = tcp_time_stamp; } /* Restart timer after forward progress on connection. - * RFC2988 recommends (and BSD does) to restart timer to now+rto, - * which is certainly wrong and effectively means that - * rto includes one more _full_ rtt. - * - * For details see: - * ftp://ftp.inr.ac.ru:/ip-routing/README.rto + * RFC2988 recommends to restart timer to now+rto. */ static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp) @@ -1700,12 +1728,7 @@ if (tp->packets_out==0) { tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS); } else { - struct sk_buff *skb = skb_peek(&sk->write_queue); - __u32 when = tp->rto + tp->rttvar - (tcp_time_stamp - TCP_SKB_CB(skb)->when); - - if ((__s32)when < (__s32)tp->rttvar) - when = tp->rttvar; - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, min(when, TCP_RTO_MAX)); + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); } } @@ -1857,12 +1880,7 @@ /* Note, it is the only place, where * fast path is recovered for sending TCP. */ - if (skb_queue_len(&tp->out_of_order_queue) == 0 && -#ifdef TCP_FORMAL_WINDOW - tcp_receive_window(tp) && -#endif - !tp->urg_data) - tcp_fast_path_on(tp); + tcp_fast_path_check(sk, tp); if (nwin > tp->max_window) { tp->max_window = nwin; @@ -1873,16 +1891,6 @@ tp->snd_una = ack; -#ifdef TCP_DEBUG - if (before(tp->snd_una + tp->snd_wnd, tp->snd_nxt)) { - if (tp->snd_nxt-(tp->snd_una + tp->snd_wnd) >= (1<<tp->snd_wscale) - && net_ratelimit()) - printk(KERN_DEBUG "TCP: peer %u.%u.%u.%u:%u/%u shrinks window %u:%u:%u. Bad, what else can I say?\n", - NIPQUAD(sk->daddr), htons(sk->dport), sk->num, - tp->snd_una, tp->snd_wnd, tp->snd_nxt); - } -#endif - return flag; } @@ -2224,7 +2232,6 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - tp->fin_seq = TCP_SKB_CB(skb)->end_seq; tcp_schedule_ack(tp); sk->shutdown |= RCV_SHUTDOWN; @@ -2506,10 +2513,27 @@ } } +static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb) +{ + return (int)skb->truesize <= sk->forward_alloc || + tcp_mem_schedule(sk, skb->truesize, 1); +} + +static int tcp_prune_queue(struct sock *sk); + static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) { + struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int eaten = 0; + int eaten = -1; + + th = skb->h.th; + __skb_pull(skb, th->doff*4); + + if (skb->len == 0 && !th->fin) + goto drop; + + TCP_ECN_accept_cwr(tp, skb); if (tp->dsack) { tp->dsack = 0; @@ -2535,26 +2559,32 @@ __set_current_state(TASK_RUNNING); local_bh_enable(); - if (memcpy_toiovec(tp->ucopy.iov, skb->data, chunk)) { + if (skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) { sk->err = EFAULT; sk->error_report(sk); } local_bh_disable(); tp->ucopy.len -= chunk; tp->copied_seq += chunk; - eaten = (chunk == skb->len && !skb->h.th->fin); + eaten = (chunk == skb->len && !th->fin); } - if (!eaten) { + if (eaten <= 0) { queue_and_out: + if (eaten < 0 && + (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + !tcp_rmem_schedule(sk, skb))) { + if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) + goto drop; + } tcp_set_owner_r(skb, sk); __skb_queue_tail(&sk->receive_queue, skb); } tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; if(skb->len) tcp_event_data_recv(sk, tp, skb); - if(skb->h.th->fin) - tcp_fin(skb, sk, skb->h.th); + if(th->fin) + tcp_fin(skb, sk, th); if (skb_queue_len(&tp->out_of_order_queue)) { tcp_ofo_queue(sk); @@ -2569,15 +2599,9 @@ if(tp->num_sacks) tcp_sack_remove(tp); - /* Turn on fast path. */ - if (skb_queue_len(&tp->out_of_order_queue) == 0 && -#ifdef TCP_FORMAL_WINDOW - tcp_receive_window(tp) && -#endif - !tp->urg_data) - tcp_fast_path_on(tp); + tcp_fast_path_check(sk, tp); - if (eaten) { + if (eaten > 0) { __kfree_skb(skb); } else if (!sk->dead) sk->data_ready(sk, 0); @@ -2592,17 +2616,12 @@ out_of_window: tcp_schedule_ack(tp); +drop: __kfree_skb(skb); return; } - /* Out of window. F.e. zero window probe. - * - * Note: it is highly possible that we may open window and enqueue - * this segment now. However, this will be known only after we queue - * it, which will result in queue full of successive 1 byte BSD - * window probes, it is SWS in fact. So, always reject it and send ACK. - */ + /* Out of window. F.e. zero window probe. */ if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt+tcp_receive_window(tp))) goto out_of_window; @@ -2626,6 +2645,12 @@ TCP_ECN_check_ce(tp, skb); + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + !tcp_rmem_schedule(sk, skb)) { + if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) + goto drop; + } + /* Disable header prediction. */ tp->pred_flags = 0; tcp_schedule_ack(tp); @@ -2704,52 +2729,142 @@ } } - -static void tcp_collapse_queue(struct sock *sk, struct sk_buff_head *q) +/* Collapse contiguous sequence of skbs head..tail with + * sequence numbers start..end. + * Segments with FIN/SYN are not collapsed (only because this + * simplifies code) + */ +static void +tcp_collapse(struct sock *sk, struct sk_buff *head, + struct sk_buff *tail, u32 start, u32 end) { - struct sk_buff *skb = skb_peek(q); - struct sk_buff *skb_next; + struct sk_buff *skb; - while (skb && - skb != (struct sk_buff *)q && - (skb_next = skb->next) != (struct sk_buff *)q) { - struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - struct tcp_skb_cb *scb_next = TCP_SKB_CB(skb_next); - - if (scb->end_seq == scb_next->seq && - skb_tailroom(skb) >= skb_next->len && -#define TCP_DONT_COLLAPSE (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN) - !(tcp_flag_word(skb->h.th)&TCP_DONT_COLLAPSE) && - !(tcp_flag_word(skb_next->h.th)&TCP_DONT_COLLAPSE)) { - /* OK to collapse two skbs to one */ - memcpy(skb_put(skb, skb_next->len), skb_next->data, skb_next->len); - __skb_unlink(skb_next, skb_next->list); - scb->end_seq = scb_next->end_seq; - __kfree_skb(skb_next); + /* First, check that queue is collapsable and find + * the point where collapsing can be useful. */ + for (skb = head; skb != tail; ) { + /* No new bits? It is possible on ofo queue. */ + if (!before(start, TCP_SKB_CB(skb)->end_seq)) { + struct sk_buff *next = skb->next; + __skb_unlink(skb, skb->list); + __kfree_skb(skb); NET_INC_STATS_BH(TCPRcvCollapsed); - } else { - /* Lots of spare tailroom, reallocate this skb to trim it. */ - if (tcp_win_from_space(skb->truesize) > skb->len && - skb_tailroom(skb) > sizeof(struct sk_buff) + 16) { - struct sk_buff *nskb; - - nskb = skb_copy_expand(skb, skb_headroom(skb), 0, GFP_ATOMIC); - if (nskb) { - tcp_set_owner_r(nskb, sk); - memcpy(nskb->data-skb_headroom(skb), - skb->data-skb_headroom(skb), - skb_headroom(skb)); - __skb_append(skb, nskb); - __skb_unlink(skb, skb->list); - __kfree_skb(skb); - } + skb = next; + continue; + } + + /* The first skb to collapse is: + * - not SYN/FIN and + * - bloated or contains data before "start" or + * overlaps to the next one. + */ + if (!skb->h.th->syn && !skb->h.th->fin && + (tcp_win_from_space(skb->truesize) > skb->len || + before(TCP_SKB_CB(skb)->seq, start) || + (skb->next != tail && + TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq))) + break; + + /* Decided to skip this, advance start seq. */ + start = TCP_SKB_CB(skb)->end_seq; + skb = skb->next; + } + if (skb == tail || skb->h.th->syn || skb->h.th->fin) + return; + + while (before(start, end)) { + struct sk_buff *nskb; + int header = skb_headroom(skb); + int copy = (PAGE_SIZE - sizeof(struct sk_buff) - + sizeof(struct skb_shared_info) - header - 31)&~15; + + /* Too big header? This can happen with IPv6. */ + if (copy < 0) + return; + if (end-start < copy) + copy = end-start; + nskb = alloc_skb(copy+header, GFP_ATOMIC); + if (!nskb) + return; + skb_reserve(nskb, header); + memcpy(nskb->head, skb->head, header); + nskb->nh.raw = nskb->head + (skb->nh.raw-skb->head); + nskb->h.raw = nskb->head + (skb->h.raw-skb->head); + nskb->mac.raw = nskb->head + (skb->mac.raw-skb->head); + memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); + TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start; + __skb_insert(nskb, skb->prev, skb, skb->list); + tcp_set_owner_r(nskb, sk); + + /* Copy data, releasing collapsed skbs. */ + while (copy > 0) { + int offset = start - TCP_SKB_CB(skb)->seq; + int size = TCP_SKB_CB(skb)->end_seq - start; + + if (offset < 0) BUG(); + if (size > 0) { + size = min(copy, size); + if (skb_copy_bits(skb, offset, skb_put(nskb, size), size)) + BUG(); + TCP_SKB_CB(nskb)->end_seq += size; + copy -= size; + start += size; + } + if (!before(start, TCP_SKB_CB(skb)->end_seq)) { + struct sk_buff *next = skb->next; + __skb_unlink(skb, skb->list); + __kfree_skb(skb); + NET_INC_STATS_BH(TCPRcvCollapsed); + skb = next; + if (skb == tail || skb->h.th->syn || skb->h.th->fin) + return; } - skb = skb_next; } } } -/* Clean the out_of_order queue if we can, trying to get +/* Collapse ofo queue. Algorithm: select contiguous sequence of skbs + * and tcp_collapse() them until all the queue is collapsed. + */ +static void tcp_collapse_ofo_queue(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb = skb_peek(&tp->out_of_order_queue); + struct sk_buff *head; + u32 start, end; + + if (skb == NULL) + return; + + start = TCP_SKB_CB(skb)->seq; + end = TCP_SKB_CB(skb)->end_seq; + head = skb; + + for (;;) { + skb = skb->next; + + /* Segment is terminated when we see gap or when + * we are at the end of all the queue. */ + if (skb == (struct sk_buff *)&tp->out_of_order_queue || + after(TCP_SKB_CB(skb)->seq, end) || + before(TCP_SKB_CB(skb)->end_seq, start)) { + tcp_collapse(sk, head, skb, start, end); + head = skb; + if (skb == (struct sk_buff *)&tp->out_of_order_queue) + break; + /* Start new segment */ + start = TCP_SKB_CB(skb)->seq; + end = TCP_SKB_CB(skb)->end_seq; + } else { + if (before(TCP_SKB_CB(skb)->seq, start)) + start = TCP_SKB_CB(skb)->seq; + if (after(TCP_SKB_CB(skb)->end_seq, end)) + end = TCP_SKB_CB(skb)->end_seq; + } + } +} + +/* Reduce allocated memory if we can, trying to get * the socket within its memory limits again. * * Return less than zero if we should start dropping frames @@ -2769,8 +2884,10 @@ else if (tcp_memory_pressure) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss); - tcp_collapse_queue(sk, &sk->receive_queue); - tcp_collapse_queue(sk, &tp->out_of_order_queue); + tcp_collapse_ofo_queue(sk); + tcp_collapse(sk, sk->receive_queue.next, + (struct sk_buff*)&sk->receive_queue, + tp->copied_seq, tp->rcv_nxt); tcp_mem_reclaim(sk); if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) @@ -2804,59 +2921,10 @@ NET_INC_STATS_BH(RcvPruned); /* Massive buffer overcommit. */ + tp->pred_flags = 0; return -1; } -static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb) -{ - return (int)skb->truesize <= sk->forward_alloc || - tcp_mem_schedule(sk, skb->truesize, 1); -} - -/* - * This routine handles the data. If there is room in the buffer, - * it will be have already been moved into it. If there is no - * room, then we will just have to discard the packet. - */ - -static void tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len) -{ - struct tcphdr *th; - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - - th = skb->h.th; - skb_pull(skb, th->doff*4); - skb_trim(skb, len - (th->doff*4)); - - if (skb->len == 0 && !th->fin) - goto drop; - - TCP_ECN_accept_cwr(tp, skb); - - /* - * If our receive queue has grown past its limits shrink it. - * Make sure to do this before moving rcv_nxt, otherwise - * data might be acked for that we don't have enough room. - */ - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || - !tcp_rmem_schedule(sk, skb)) { - if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) - goto drop; - } - - tcp_data_queue(sk, skb); - -#ifdef TCP_DEBUG - if (before(tp->rcv_nxt, tp->copied_seq)) { - printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n"); - tp->rcv_nxt = tp->copied_seq; - } -#endif - return; - -drop: - __kfree_skb(skb); -} /* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. * As additional protections, we do not touch cwnd in retransmission phases, @@ -2937,7 +3005,7 @@ if (after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) || tcp_packets_in_flight(tp) >= tp->snd_cwnd || - tcp_write_xmit(sk)) + tcp_write_xmit(sk, tp->nonagle)) tcp_check_probe_timer(sk, tp); } @@ -3009,6 +3077,19 @@ if (after(tp->copied_seq, ptr)) return; + /* Do not replay urg ptr. + * + * NOTE: interesting situation not covered by specs. + * Misbehaving sender may send urg ptr, pointing to segment, + * which we already have in ofo queue. We are not able to fetch + * such data and will stay in TCP_URG_NOTYET until will be eaten + * by recvmsg(). Seems, we are not obliged to handle such wicked + * situations. But it is worth to think about possibility of some + * DoSes using some hypothetical application level deadlock. + */ + if (before(ptr, tp->rcv_nxt)) + return; + /* Do we already have a newer (or duplicate) urgent pointer? */ if (tp->urg_data && !after(ptr, tp->urg_seq)) return; @@ -3027,9 +3108,27 @@ * tp->copied_seq since we would read the last urgent byte again * as data, nor can we alter copied_seq until this data arrives * or we break the sematics of SIOCATMARK (and thus sockatmark()) - */ - if (tp->urg_seq == tp->copied_seq) - tp->copied_seq++; /* Move the copied sequence on correctly */ + * + * NOTE. Double Dutch. Rendering to plain English: author of comment + * above did something sort of send("A", MSG_OOB); send("B", MSG_OOB); + * and expect that both A and B disappear from stream. This is _wrong_. + * Though this happens in BSD with high probability, this is occasional. + * Any application relying on this is buggy. Note also, that fix "works" + * only in this artificial test. Insert some normal data between A and B and we will + * decline of BSD again. Verdict: it is better to remove to trap + * buggy users. + */ + if (tp->urg_seq == tp->copied_seq && tp->urg_data && + !sk->urginline && + tp->copied_seq != tp->rcv_nxt) { + struct sk_buff *skb = skb_peek(&sk->receive_queue); + tp->copied_seq++; + if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) { + __skb_unlink(skb, skb->list); + __kfree_skb(skb); + } + } + tp->urg_data = TCP_URG_NOTYET; tp->urg_seq = ptr; @@ -3038,7 +3137,7 @@ } /* This is the 'fast' part of urgent handling. */ -static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len) +static inline void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -3048,11 +3147,14 @@ /* Do we wait for any urgent data? - normally not... */ if (tp->urg_data == TCP_URG_NOTYET) { - u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4); + u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - th->syn; /* Is the urgent pointer pointing into this packet? */ - if (ptr < len) { - tp->urg_data = TCP_URG_VALID | *(ptr + (unsigned char *) th); + if (ptr < skb->len) { + u8 tmp; + if (skb_copy_bits(skb, ptr, &tmp, 1)) + BUG(); + tp->urg_data = TCP_URG_VALID | tmp; if (!sk->dead) sk->data_ready(sk,0); } @@ -3067,9 +3169,9 @@ local_bh_enable(); if (skb->ip_summed==CHECKSUM_UNNECESSARY) - err = memcpy_toiovec(tp->ucopy.iov, skb->h.raw + hlen, chunk); + err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk); else - err = copy_and_csum_toiovec(tp->ucopy.iov, skb, hlen); + err = skb_copy_and_csum_datagram_iovec(skb, hlen, tp->ucopy.iov); if (!err) { update: @@ -3117,32 +3219,6 @@ * disabled when: * - A zero window was announced from us - zero window probing * is only handled properly in the slow path. - * [ NOTE: actually, it was made incorrectly and nobody ever noticed - * this! Reason is clear: 1. Correct senders do not send - * to zero window. 2. Even if a sender sends to zero window, - * nothing terrible occurs. - * - * For now I cleaned this and fast path is really always disabled, - * when window is zero, but I would be more happy to remove these - * checks. Code will be only cleaner and _faster_. --ANK - * - * Later note. I've just found that slow path also accepts - * out of window segments, look at tcp_sequence(). So... - * it is the last argument: I repair all and comment out - * repaired code by TCP_FORMAL_WINDOW. - * [ I remember one rhyme from a chidren's book. (I apologize, - * the trasnlation is not rhymed 8)): people in one (jewish) village - * decided to build sauna, but divided to two parties. - * The first one insisted that battens should not be dubbed, - * another objected that foots will suffer of splinters, - * the first fended that dubbed wet battens are too slippy - * and people will fall and it is much more serious! - * Certaiinly, all they went to rabbi. - * After some thinking, he judged: "Do not be lazy! - * Certainly, dub the battens! But put them by dubbed surface down." - * ] - * ] - * * - Out of order segments arrived. * - Urgent data is expected. * - There is no buffer space left @@ -3348,7 +3424,7 @@ tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); - if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { TCP_INC_STATS_BH(TcpInErrs); NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); @@ -3360,10 +3436,10 @@ tcp_ack(sk, skb, FLAG_SLOWPATH); /* Process urgent data. */ - tcp_urg(sk, th, len); + tcp_urg(sk, skb, th); /* step 7: process the segment text */ - tcp_data(skb, sk, len); + tcp_data_queue(sk, skb); tcp_data_snd_check(sk); tcp_ack_snd_check(sk); @@ -3452,8 +3528,6 @@ */ tp->snd_wnd = ntohs(th->window); tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq); - tp->syn_seq = TCP_SKB_CB(skb)->seq; - tp->fin_seq = TCP_SKB_CB(skb)->seq; if (tp->wscale_ok == 0) { tp->snd_wscale = tp->rcv_wscale = 0; @@ -3488,7 +3562,7 @@ /* Remember, tcp_poll() does not lock socket! * Change state from SYN-SENT only after copied_seq - * is initilized. */ + * is initialized. */ tp->copied_seq = tp->rcv_nxt; mb(); tcp_set_state(sk, TCP_ESTABLISHED); @@ -3498,7 +3572,7 @@ sk_wake_async(sk, 0, POLL_OUT); } - if (tp->write_pending || tp->defer_accept) { + if (tp->write_pending || tp->defer_accept || tp->ack.pingpong) { /* Save one ACK. Data will be ready after * several ticks, if write_pending is set. * @@ -3508,6 +3582,8 @@ */ tcp_schedule_ack(tp); tp->ack.lrcvtime = tcp_time_stamp; + tp->ack.ato = TCP_ATO_MIN; + tcp_incr_quickack(tp); tcp_enter_quickack_mode(tp); tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX); @@ -3683,21 +3759,9 @@ /* step 4: * - * Check for a SYN, and ensure it matches the SYN we were - * first sent. We have to handle the rather unusual (but valid) - * sequence that KA9Q derived products may generate of - * - * SYN - * SYN|ACK Data - * ACK (lost) - * SYN|ACK Data + More Data - * .. we must ACK not RST... - * - * We keep syn_seq as the sequence space occupied by the - * original syn. + * Check for a SYN in window. */ - - if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); return 1; @@ -3806,13 +3870,13 @@ step6: /* step 6: check the URG bit */ - tcp_urg(sk, th, len); + tcp_urg(sk, skb, th); /* step 7: process the segment text */ switch (sk->state) { case TCP_CLOSE_WAIT: case TCP_CLOSING: - if (!before(TCP_SKB_CB(skb)->seq, tp->fin_seq)) + if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) break; case TCP_FIN_WAIT1: case TCP_FIN_WAIT2: @@ -3830,7 +3894,7 @@ } /* Fall through */ case TCP_ESTABLISHED: - tcp_data(skb, sk, len); + tcp_data_queue(sk, skb); queued = 1; break; } diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.4.3/linux/net/ipv4/tcp_ipv4.c Mon Jan 1 11:01:58 2001 +++ linux/net/ipv4/tcp_ipv4.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.222 2000/12/08 17:15:53 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.228 2001/04/06 18:41:36 davem Exp $ * * IPv4 specific functions * @@ -670,6 +670,7 @@ } __sk_dst_set(sk, &rt->u.dst); + sk->route_caps = rt->u.dst.dev->features; if (!sk->protinfo.af_inet.opt || !sk->protinfo.af_inet.opt->srr) daddr = rt->rt_dst; @@ -717,6 +718,7 @@ tp->ext_header_len = 0; if (sk->protinfo.af_inet.opt) tp->ext_header_len = sk->protinfo.af_inet.opt->optlen; + sk->protinfo.af_inet.id = tp->write_seq^jiffies; tp->mss_clamp = 536; @@ -726,6 +728,7 @@ failure: __sk_dst_reset(sk); + sk->route_caps = 0; sk->dport = 0; return err; } @@ -850,32 +853,21 @@ * */ -void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) +void tcp_v4_err(struct sk_buff *skb, u32 info) { - struct iphdr *iph = (struct iphdr*)dp; - struct tcphdr *th; + struct iphdr *iph = (struct iphdr*)skb->data; + struct tcphdr *th = (struct tcphdr*)(skb->data+(iph->ihl<<2)); struct tcp_opt *tp; int type = skb->h.icmph->type; int code = skb->h.icmph->code; -#if ICMP_MIN_LENGTH < 14 - int no_flags = 0; -#else -#define no_flags 0 -#endif struct sock *sk; __u32 seq; int err; - if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) { + if (skb->len < (iph->ihl << 2) + 8) { ICMP_INC_STATS_BH(IcmpInErrors); return; } -#if ICMP_MIN_LENGTH < 14 - if (len < (iph->ihl << 2) + 14) - no_flags = 1; -#endif - - th = (struct tcphdr*)(dp+(iph->ihl<<2)); sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, tcp_v4_iif(skb)); if (sk == NULL) { @@ -921,7 +913,7 @@ if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */ if (sk->lock.users == 0) - do_pmtu_discovery(sk, iph, ntohs(skb->h.icmph->un.frag.mtu)); + do_pmtu_discovery(sk, iph, info); goto out; } @@ -940,15 +932,6 @@ if (sk->lock.users != 0) goto out; - /* The final ACK of the handshake should be already - * handled in the new socket context, not here. - * Strictly speaking - an ICMP error for the final - * ACK should set the opening flag, but that is too - * complicated right now. - */ - if (!no_flags && !th->syn && !th->ack) - goto out; - req = tcp_v4_search_req(tp, iph, th, &prev); if (!req) goto out; @@ -976,8 +959,6 @@ case TCP_SYN_RECV: /* Cannot happen. It can f.e. if SYNs crossed. */ - if (!no_flags && !th->syn) - goto out; if (sk->lock.users == 0) { TCP_INC_STATS_BH(TcpAttemptFails); sk->err = err; @@ -1023,8 +1004,13 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, struct sk_buff *skb) { - th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr, - csum_partial((char *)th, th->doff<<2, skb->csum)); + if (skb->ip_summed == CHECKSUM_HW) { + th->check = ~tcp_v4_check(th, len, sk->saddr, sk->daddr, 0); + skb->csum = offsetof(struct tcphdr, check); + } else { + th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr, + csum_partial((char *)th, th->doff<<2, skb->csum)); + } } /* @@ -1445,6 +1431,7 @@ goto exit; newsk->dst_cache = dst; + newsk->route_caps = dst->dev->features; newtp = &(newsk->tp_pinfo.af_tcp); newsk->daddr = req->af.v4_req.rmt_addr; @@ -1457,6 +1444,7 @@ newtp->ext_header_len = 0; if (newsk->protinfo.af_inet.opt) newtp->ext_header_len = newsk->protinfo.af_inet.opt->optlen; + newsk->protinfo.af_inet.id = newtp->write_seq^jiffies; tcp_sync_mss(newsk, dst->pmtu); newtp->advmss = dst->advmss; @@ -1512,23 +1500,23 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_HW) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (!tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, + skb->nh.iph->daddr,skb->csum)) + return 0; + + NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n")); + skb->ip_summed = CHECKSUM_NONE; + } + if (skb->len <= 76) { if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, - skb->nh.iph->daddr,skb->csum)) { - NETDEBUG(printk(KERN_DEBUG "hw tcp v4 csum failed\n")); + skb->nh.iph->daddr, + skb_checksum(skb, 0, skb->len, 0))) return -1; - } skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - if (skb->len <= 76) { - if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, - skb->nh.iph->daddr, - csum_partial((char *)skb->h.th, skb->len, 0))) - return -1; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, - skb->nh.iph->daddr,0); - } + skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, + skb->nh.iph->daddr,0); } return 0; } @@ -1601,7 +1589,7 @@ * From tcp_input.c */ -int tcp_v4_rcv(struct sk_buff *skb, unsigned short len) +int tcp_v4_rcv(struct sk_buff *skb) { struct tcphdr *th; struct sock *sk; @@ -1610,31 +1598,35 @@ if (skb->pkt_type!=PACKET_HOST) goto discard_it; - th = skb->h.th; - - /* Pull up the IP header. */ - __skb_pull(skb, skb->h.raw - skb->data); - /* Count it even if it's bad */ TCP_INC_STATS_BH(TcpInSegs); + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) + goto discard_it; + + th = skb->h.th; + + if (th->doff < sizeof(struct tcphdr)/4) + goto bad_packet; + if (!pskb_may_pull(skb, th->doff*4)) + goto discard_it; + /* An explanation is required here, I think. * Packet length and doff are validated by header prediction, * provided case of th->doff==0 is elimineted. * So, we defer the checks. */ - if (th->doff < sizeof(struct tcphdr)/4 || - (skb->ip_summed != CHECKSUM_UNNECESSARY && + if ((skb->ip_summed != CHECKSUM_UNNECESSARY && tcp_v4_checksum_init(skb) < 0)) goto bad_packet; + th = skb->h.th; TCP_SKB_CB(skb)->seq = ntohl(th->seq); TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - len - th->doff*4); + skb->len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->when = 0; TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; TCP_SKB_CB(skb)->sacked = 0; - skb->used = 0; sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb)); @@ -1665,7 +1657,7 @@ return ret; no_tcp_socket: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); } else { @@ -1682,7 +1674,7 @@ goto discard_it; do_time_wait: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); goto discard_and_relse; } @@ -1740,7 +1732,7 @@ return err; __sk_dst_set(sk, &rt->u.dst); - /* sk->route_caps = rt->u.dst.dev->features; */ + sk->route_caps = rt->u.dst.dev->features; new_saddr = rt->rt_src; @@ -1788,20 +1780,19 @@ sk->bound_dev_if); if (!err) { __sk_dst_set(sk, &rt->u.dst); - /* sk->route_caps = rt->u.dst.dev->features; */ + sk->route_caps = rt->u.dst.dev->features; return 0; } /* Routing failed... */ - /* sk->route_caps = 0; */ + sk->route_caps = 0; if (!sysctl_ip_dynaddr || sk->state != TCP_SYN_SENT || (sk->userlocks & SOCK_BINDADDR_LOCK) || - (err = tcp_v4_reselect_saddr(sk)) != 0) { + (err = tcp_v4_reselect_saddr(sk)) != 0) sk->err_soft=-err; - /* sk->error_report(sk); */ - } + return err; } @@ -1940,7 +1931,7 @@ /* Cleanup up the write buffer. */ tcp_writequeue_purge(sk); - /* Cleans up our, hopefuly empty, out_of_order_queue. */ + /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); /* Clean prequeue, it must be empty really */ @@ -1950,6 +1941,10 @@ if(sk->prev != NULL) tcp_put_port(sk); + /* If sendmsg cached page exists, toss it. */ + if (tp->sndmsg_page != NULL) + __free_page(tp->sndmsg_page); + atomic_dec(&tcp_sockets_allocated); return 0; @@ -2076,7 +2071,7 @@ if (pos >= offset) { get_tcp_sock(sk, tmpbuf, num); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if (len >= length) { + if (pos >= offset + length) { tcp_listen_unlock(); goto out_no_bh; } @@ -2097,7 +2092,7 @@ continue; get_openreq(sk, req, tmpbuf, num, uid); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock_bh(&tp->syn_wait_lock); tcp_listen_unlock(); goto out_no_bh; @@ -2129,7 +2124,7 @@ continue; get_tcp_sock(sk, tmpbuf, num); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2144,7 +2139,7 @@ continue; get_timewait_sock(tw, tmpbuf, num); len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2159,7 +2154,7 @@ begin = len - (pos - offset); *start = buffer + begin; len -= begin; - if(len > length) + if (len > length) len = length; if (len < 0) len = 0; diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_minisocks.c linux/net/ipv4/tcp_minisocks.c --- v2.4.3/linux/net/ipv4/tcp_minisocks.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv4/tcp_minisocks.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_minisocks.c,v 1.5 2000/11/28 17:04:10 davem Exp $ + * Version: $Id: tcp_minisocks.c,v 1.9 2001/03/06 22:42:56 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -105,7 +105,7 @@ * lifetime in the internet, which results in wrong conclusion, that * it is set to catch "old duplicate segments" wandering out of their path. * It is not quite correct. This timeout is calculated so that it exceeds - * maximal retransmision timeout enough to allow to lose one (or more) + * maximal retransmission timeout enough to allow to lose one (or more) * segments sent by peer and our ACKs. This time may be calculated from RTO. * * When TIME-WAIT socket receives RST, it means that another end * finally closed and we are allowed to kill TIME-WAIT too. @@ -155,7 +155,7 @@ if (th->rst) goto kill; - if (th->syn && TCP_SKB_CB(skb)->seq != tw->syn_seq) + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) goto kill_with_rst; /* Dup ACK? */ @@ -377,7 +377,6 @@ tw->rcv_nxt = tp->rcv_nxt; tw->snd_nxt = tp->snd_nxt; tw->rcv_wnd = tcp_receive_window(tp); - tw->syn_seq = tp->syn_seq; tw->ts_recent = tp->ts_recent; tw->ts_recent_stamp= tp->ts_recent_stamp; tw->pprev_death = NULL; @@ -691,8 +690,6 @@ newtp->snd_una = req->snt_isn + 1; newtp->snd_sml = req->snt_isn + 1; - tcp_delack_init(newtp); - tcp_prequeue_init(newtp); tcp_init_wl(newtp, req->snt_isn, req->rcv_isn); @@ -734,8 +731,6 @@ newtp->probes_out = 0; newtp->num_sacks = 0; - newtp->syn_seq = req->rcv_isn; - newtp->fin_seq = req->rcv_isn; newtp->urg_data = 0; newtp->listen_opt = NULL; newtp->accept_queue = newtp->accept_queue_tail = NULL; @@ -822,7 +817,7 @@ } } - /* Check for pure retransmited SYN. */ + /* Check for pure retransmitted SYN. */ if (TCP_SKB_CB(skb)->seq == req->rcv_isn && flg == TCP_FLAG_SYN && !paws_reject) { diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.4.3/linux/net/ipv4/tcp_output.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv4/tcp_output.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.129 2000/11/28 17:04:10 davem Exp $ + * Version: $Id: tcp_output.c,v 1.136 2001/03/06 22:42:56 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -166,20 +166,9 @@ /* RFC1323 scaling applied */ new_win >>= tp->rcv_wscale; -#ifdef TCP_FORMAL_WINDOW - if (new_win == 0) { - /* If we advertise zero window, disable fast path. */ + /* If we advertise zero window, disable fast path. */ + if (new_win == 0) tp->pred_flags = 0; - } else if (cur_win == 0 && tp->pred_flags == 0 && - skb_queue_len(&tp->out_of_order_queue) == 0 && - !tp->urg_data) { - /* If we open zero window, enable fast path. - Without this it will be open by the first data packet, - it is too late to merge checksumming to copy. - */ - tcp_fast_path_on(tp); - } -#endif return new_win; } @@ -337,6 +326,91 @@ tp->send_head = skb; } +/* Send _single_ skb sitting at the send head. This function requires + * true push pending frames to setup probe timer etc. + */ +void tcp_push_one(struct sock *sk, unsigned cur_mss) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb = tp->send_head; + + if (tcp_snd_test(tp, skb, cur_mss, 1)) { + /* Send it out now. */ + TCP_SKB_CB(skb)->when = tcp_time_stamp; + if (tcp_transmit_skb(sk, skb_clone(skb, sk->allocation)) == 0) { + tp->send_head = NULL; + tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; + if (tp->packets_out++ == 0) + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + return; + } + } +} + +/* Split fragmented skb to two parts at length len. */ + +static void skb_split(struct sk_buff *skb, struct sk_buff *skb1, u32 len) +{ + int i; + int pos = skb->len - skb->data_len; + + if (len < pos) { + /* Split line is inside header. */ + memcpy(skb_put(skb1, pos-len), skb->data + len, pos-len); + + /* And move data appendix as is. */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i]; + + skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags; + skb_shinfo(skb)->nr_frags = 0; + + skb1->data_len = skb->data_len; + skb1->len += skb1->data_len; + skb->data_len = 0; + skb->len = len; + skb->tail = skb->data+len; + } else { + int k = 0; + int nfrags = skb_shinfo(skb)->nr_frags; + + /* Second chunk has no header, nothing to copy. */ + + skb_shinfo(skb)->nr_frags = 0; + skb1->len = skb1->data_len = skb->len - len; + skb->len = len; + skb->data_len = len - pos; + + for (i=0; i<nfrags; i++) { + int size = skb_shinfo(skb)->frags[i].size; + if (pos + size > len) { + skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i]; + + if (pos < len) { + /* Split frag. + * We have to variants in this case: + * 1. Move all the frag to the second + * part, if it is possible. F.e. + * this approach is mandatory for TUX, + * where splitting is expensive. + * 2. Split is accurately. We make this. + */ + get_page(skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb1)->frags[0].page_offset += (len-pos); + skb_shinfo(skb1)->frags[0].size -= (len-pos); + skb_shinfo(skb)->frags[i].size = len-pos; + skb_shinfo(skb)->nr_frags++; + } + k++; + } else { + skb_shinfo(skb)->nr_frags++; + } + pos += size; + } + skb_shinfo(skb1)->nr_frags = k; + } +} + /* Function to create two new TCP segments. Shrinks the given segment * to the specified size and appends a new segment with the rest of the * packet to the list. This won't be called frequently, I hope. @@ -349,19 +423,22 @@ int nsize = skb->len - len; u16 flags; + if (skb_cloned(skb) && + skb_is_nonlinear(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -ENOMEM; + /* Get a new skb... force flag on. */ - buff = tcp_alloc_skb(sk, nsize + MAX_TCP_HEADER, GFP_ATOMIC); + buff = tcp_alloc_skb(sk, nsize, GFP_ATOMIC); if (buff == NULL) return -ENOMEM; /* We'll just try again later. */ tcp_charge_skb(sk, buff); - /* Reserve space for headers. */ - skb_reserve(buff, MAX_TCP_HEADER); - /* Correct the sequence numbers. */ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; - + TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; + /* PSH and FIN should only be set in the second packet. */ flags = TCP_SKB_CB(skb)->flags; TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); @@ -371,18 +448,22 @@ tp->lost_out++; tp->left_out++; } - TCP_SKB_CB(buff)->sacked &= ~TCPCB_AT_TAIL; + TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; - /* Copy and checksum data tail into the new buffer. */ - buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), - nsize, 0); + if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { + /* Copy and checksum data tail into the new buffer. */ + buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), + nsize, 0); - /* This takes care of the FIN sequence number too. */ - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; - skb_trim(skb, len); + skb_trim(skb, len); - /* Rechecksum original buffer. */ - skb->csum = csum_partial(skb->data, skb->len, 0); + skb->csum = csum_block_sub(skb->csum, buff->csum, len); + } else { + skb->ip_summed = CHECKSUM_HW; + skb_split(skb, buff, len); + } + + buff->ip_summed = skb->ip_summed; /* Looks stupid, but our code really uses when of * skbs, which it never sent before. --ANK @@ -461,7 +542,7 @@ * Returns 1, if no segments are in flight and we have queued segments, but * cannot send anything now because of SWS or another problem. */ -int tcp_write_xmit(struct sock *sk) +int tcp_write_xmit(struct sock *sk, int nonagle) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); unsigned int mss_now; @@ -482,7 +563,7 @@ mss_now = tcp_current_mss(sk); while((skb = tp->send_head) && - tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? tp->nonagle : 1)) { + tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : 1)) { if (skb->len > mss_now) { if (tcp_fragment(sk, skb, mss_now)) break; @@ -568,22 +649,21 @@ * but may be worse for the performance because of rcv_mss * fluctuations. --SAW 1998/11/1 */ - unsigned int mss = tp->ack.rcv_mss; - int free_space; - u32 window; - - /* Sometimes free_space can be < 0. */ - free_space = tcp_space(sk); - if (tp->window_clamp < mss) - mss = tp->window_clamp; + int mss = tp->ack.rcv_mss; + int free_space = tcp_space(sk); + int full_space = min(tp->window_clamp, tcp_full_space(sk)); + int window; + + if (mss > full_space) + mss = full_space; - if (free_space < (int)min(tp->window_clamp, tcp_full_space(sk)) / 2) { + if (free_space < full_space/2) { tp->ack.quick = 0; if (tcp_memory_pressure) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss); - if (free_space < ((int)mss)) + if (free_space < mss) return 0; } @@ -599,9 +679,8 @@ * is too small. */ window = tp->rcv_wnd; - if ((((int) window) <= (free_space - ((int) mss))) || - (((int) window) > free_space)) - window = (((unsigned int) free_space)/mss)*mss; + if (window <= free_space - mss || window > free_space) + window = (free_space/mss)*mss; return window; } @@ -638,19 +717,14 @@ /* Ok. We will be able to collapse the packet. */ __skb_unlink(next_skb, next_skb->list); - if(skb->len % 4) { - /* Must copy and rechecksum all data. */ + if (next_skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_HW; + + if (skb->ip_summed != CHECKSUM_HW) { memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size); - skb->csum = csum_partial(skb->data, skb->len, 0); - } else { - /* Optimize, actually we could also combine next_skb->csum - * to skb->csum using a single add w/carry operation too. - */ - skb->csum = csum_partial_copy_nocheck(next_skb->data, - skb_put(skb, next_skb_size), - next_skb_size, skb->csum); + skb->csum = csum_block_add(skb->csum, next_skb->csum, skb->len); } - + /* Update sequence range on original skb. */ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq; @@ -668,11 +742,12 @@ tp->lost_out--; tp->left_out--; } + /* Reno case is special. Sigh... */ if (!tp->sack_ok && tp->sacked_out) { - /* Reno case is special. Sigh... */ tp->sacked_out--; tp->left_out--; } + /* Not quite right: it can be > snd.fack, but * it is better to underestimate fackets. */ @@ -712,7 +787,7 @@ if (!lost) return; - tp->left_out = tp->sacked_out + tp->lost_out; + tcp_sync_left_out(tp); /* Don't muck with the congestion window here. * Reason is that we do not increase amount of _data_ @@ -745,6 +820,15 @@ if (atomic_read(&sk->wmem_alloc) > min(sk->wmem_queued+(sk->wmem_queued>>2),sk->sndbuf)) return -EAGAIN; + /* If receiver has shrunk his window, and skb is out of + * new window, do not retransmit it. The exception is the + * case, when window is shrunk to zero. In this case + * our retransmit serves as a zero window probe. + */ + if (!before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd) + && TCP_SKB_CB(skb)->seq != tp->snd_una) + return -EAGAIN; + if(skb->len > cur_mss) { if(tcp_fragment(sk, skb, cur_mss)) return -ENOMEM; /* We'll try again later. */ @@ -758,6 +842,7 @@ (skb->len < (cur_mss >> 1)) && (skb->next != tp->send_head) && (skb->next != (struct sk_buff *)&sk->write_queue) && + (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(skb->next)->nr_frags == 0) && (sysctl_tcp_retrans_collapse != 0)) tcp_retrans_try_collapse(sk, skb, cur_mss); @@ -771,9 +856,11 @@ if(skb->len > 0 && (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) && tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { - TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; - skb_trim(skb, 0); - skb->csum = 0; + if (!pskb_trim(skb, 0)) { + TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; + skb->ip_summed = CHECKSUM_NONE; + skb->csum = 0; + } } /* Make a copy, if the first transmission SKB clone we made @@ -782,7 +869,7 @@ TCP_SKB_CB(skb)->when = tcp_time_stamp; err = tcp_transmit_skb(sk, (skb_cloned(skb) ? - skb_copy(skb, GFP_ATOMIC): + pskb_copy(skb, GFP_ATOMIC): skb_clone(skb, GFP_ATOMIC))); if (err == 0) { @@ -912,28 +999,10 @@ */ mss_now = tcp_current_mss(sk); - /* Please, find seven differences of 2.3.33 and loook - * what I broke here. 8) --ANK - */ - if(tp->send_head != NULL) { - /* tcp_write_xmit() takes care of the rest. */ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN; TCP_SKB_CB(skb)->end_seq++; tp->write_seq++; - - /* Special case to avoid Nagle bogosity. If this - * segment is the last segment, and it was queued - * due to Nagle/SWS-avoidance, send it out now. - */ - if(tp->send_head == skb && - !after(tp->write_seq, tp->snd_una + tp->snd_wnd)) { - TCP_SKB_CB(skb)->when = tcp_time_stamp; - if (!tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL))) - update_send_head(sk, tp, skb); - else - tcp_check_probe_timer(sk, tp); - } } else { /* Socket is locked, keep trying until memory is available. */ for (;;) { @@ -953,9 +1022,9 @@ /* FIN eats a sequence byte, write_seq advanced by tcp_send_skb(). */ TCP_SKB_CB(skb)->seq = tp->write_seq; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; - tcp_send_skb(sk, skb, 0, mss_now); - __tcp_push_pending_frames(sk, tp, mss_now, 1); + tcp_send_skb(sk, skb, 1, mss_now); } + __tcp_push_pending_frames(sk, tp, mss_now, 1); } /* We get here when a process closes a file descriptor (either due to @@ -1224,23 +1293,6 @@ tp->ack.timeout = timeout; if (!mod_timer(&tp->delack_timer, timeout)) sock_hold(sk); - -#ifdef TCP_FORMAL_WINDOW - /* Explanation. Header prediction path does not handle - * case of zero window. If we send ACK immediately, pred_flags - * are reset when sending ACK. If rcv_nxt is advanced and - * ack is not sent, than delayed ack is scheduled. - * Hence, it is the best place to check for zero window. - */ - if (tp->pred_flags) { - if (tcp_receive_window(tp) == 0) - tp->pred_flags = 0; - } else { - if (skb_queue_len(&tp->out_of_order_queue) == 0 && - !tp->urg_data) - tcp_fast_path_on(tp); - } -#endif } /* This routine sends an ack and also updates the window. */ diff -u --recursive --new-file v2.4.3/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.4.3/linux/net/ipv4/tcp_timer.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/tcp_timer.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.81 2001/01/01 02:38:30 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.83 2001/03/07 22:00:57 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -326,6 +326,29 @@ BUG_TRAP(!skb_queue_empty(&sk->write_queue)); + if (tp->snd_wnd == 0 && !sk->dead && + !((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV))) { + /* Receiver dastardly shrinks window. Our retransmits + * become zero probes, but we should not timeout this + * connection. If the socket is an orphan, time it out, + * we cannot allow such beasts to hang infinitely. + */ +#ifdef TCP_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", + NIPQUAD(sk->daddr), htons(sk->dport), sk->num, + tp->snd_una, tp->snd_nxt); +#endif + if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) { + tcp_write_err(sk); + goto out; + } + tcp_enter_loss(sk, 0); + tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)); + __sk_dst_reset(sk); + goto out_reset_timer; + } + if (tcp_write_timeout(sk)) goto out; @@ -379,6 +402,8 @@ */ tp->backoff++; tp->retransmits++; + +out_reset_timer: tp->rto = min(tp->rto << 1, TCP_RTO_MAX); tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); if (tp->retransmits > sysctl_tcp_retries1) diff -u --recursive --new-file v2.4.3/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.4.3/linux/net/ipv4/udp.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/udp.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.91 2000/11/28 13:38:38 davem Exp $ + * Version: $Id: udp.c,v 1.98 2001/03/06 21:15:10 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -291,22 +291,16 @@ * to find the appropriate port. */ -void udp_err(struct sk_buff *skb, unsigned char *dp, int len) +void udp_err(struct sk_buff *skb, u32 info) { - struct iphdr *iph = (struct iphdr*)dp; - struct udphdr *uh = (struct udphdr*)(dp+(iph->ihl<<2)); + struct iphdr *iph = (struct iphdr*)skb->data; + struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct sock *sk; int harderr; - u32 info; int err; - if (len < (iph->ihl<<2)+sizeof(struct udphdr)) { - ICMP_INC_STATS_BH(IcmpInErrors); - return; - } - sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); if (sk == NULL) { ICMP_INC_STATS_BH(IcmpInErrors); @@ -314,7 +308,6 @@ } err = 0; - info = 0; harderr = 0; switch (type) { @@ -326,14 +319,12 @@ goto out; case ICMP_PARAMETERPROB: err = EPROTO; - info = ntohl(skb->h.icmph->un.gateway)>>24; harderr = 1; break; case ICMP_DEST_UNREACH: if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT) { err = EMSGSIZE; - info = ntohs(skb->h.icmph->un.frag.mtu); harderr = 1; break; } @@ -379,10 +370,7 @@ }; /* - * Copy and checksum a UDP packet from user space into a buffer. We still have - * to do the planning to get ip_build_xmit to spot direct transfer to network - * card and provide an additional callback mode for direct user->board I/O - * transfers. That one will be fun. + * Copy and checksum a UDP packet from user space into a buffer. */ static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) @@ -409,10 +397,7 @@ } /* - * Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing - * that we use two routines for this for speed. Probably we ought to have a - * CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding. - * Timing needed to verify if this is a valid decision. + * Copy a UDP packet from user space into a buffer without checksumming. */ static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) @@ -625,7 +610,7 @@ static __inline__ int __udp_checksum_complete(struct sk_buff *skb) { - return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)); + return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); } static __inline__ int udp_checksum_complete(struct sk_buff *skb) @@ -655,11 +640,6 @@ if (flags & MSG_ERRQUEUE) return ip_recv_error(sk, msg, len); - /* - * From here the generic datagram does a lot of the work. Come - * the finished NET3, it will do _ALL_ the work! - */ - skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -679,9 +659,9 @@ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else { - err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr)); + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - if (err) + if (err == -EINVAL) goto csum_copy_err; } @@ -758,6 +738,7 @@ sk->daddr = rt->rt_dst; sk->dport = usin->sin_port; sk->state = TCP_ESTABLISHED; + sk->protinfo.af_inet.id = jiffies; sk_dst_set(sk, &rt->u.dst); return(0); @@ -872,10 +853,13 @@ if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_HW) { - if (udp_check(uh, ulen, saddr, daddr, skb->csum)) - return -1; skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) + if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) + return 0; + NETDEBUG(printk(KERN_DEBUG "udp v4 hw csum failure.\n")); + skb->ip_summed = CHECKSUM_NONE; + } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). @@ -887,7 +871,7 @@ * All we need to do is get the socket, and then do a checksum. */ -int udp_rcv(struct sk_buff *skb, unsigned short len) +int udp_rcv(struct sk_buff *skb) { struct sock *sk; struct udphdr *uh; @@ -895,29 +879,22 @@ struct rtable *rt = (struct rtable*)skb->dst; u32 saddr = skb->nh.iph->saddr; u32 daddr = skb->nh.iph->daddr; - - /* - * Get the header. - */ - - uh = skb->h.uh; - __skb_pull(skb, skb->h.raw - skb->data); + int len = skb->len; IP_INC_STATS_BH(IpInDelivers); /* * Validate the packet and the UDP length. */ - - ulen = ntohs(uh->len); + ulen = ntohs(skb->h.uh->len); - if (ulen > len || ulen < sizeof(*uh)) { - NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len)); - UDP_INC_STATS_BH(UdpInErrors); - kfree_skb(skb); - return(0); - } - skb_trim(skb, ulen); + if (ulen > len || ulen < sizeof(*uh)) + goto short_packet; + + if (pskb_trim(skb, ulen)) + goto short_packet; + + uh = skb->h.uh; if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) goto csum_error; @@ -944,6 +921,12 @@ * Hmm. We got an UDP packet to a port to which we * don't wanna listen. Ignore it. */ + kfree_skb(skb); + return(0); + +short_packet: + NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len)); + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); diff -u --recursive --new-file v2.4.3/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.4.3/linux/net/ipv6/af_inet6.c Mon Oct 23 15:48:28 2000 +++ linux/net/ipv6/af_inet6.c Thu Apr 12 12:11:39 2001 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.60 2000/10/19 01:05:34 davem Exp $ + * $Id: af_inet6.c,v 1.63 2001/03/02 03:13:05 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -461,6 +461,7 @@ sendmsg: inet_sendmsg, /* ok */ recvmsg: inet_recvmsg, /* ok */ mmap: sock_no_mmap, + sendpage: tcp_sendpage }; struct proto_ops inet6_dgram_ops = { @@ -481,6 +482,7 @@ sendmsg: inet_sendmsg, /* ok */ recvmsg: inet_recvmsg, /* ok */ mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family inet6_family_ops = { diff -u --recursive --new-file v2.4.3/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c --- v2.4.3/linux/net/ipv6/datagram.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv6/datagram.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: datagram.c,v 1.21 2000/11/28 13:42:08 davem Exp $ + * $Id: datagram.c,v 1.22 2000/12/13 18:31:50 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -57,7 +57,7 @@ serr->port = port; skb->h.raw = payload; - skb_pull(skb, payload - skb->data); + __skb_pull(skb, payload - skb->data); if (sock_queue_err_skb(sk, skb)) kfree_skb(skb); @@ -92,7 +92,7 @@ serr->port = fl->uli_u.ports.dport; skb->h.raw = skb->tail; - skb_pull(skb, skb->tail - skb->data); + __skb_pull(skb, skb->tail - skb->data); if (sock_queue_err_skb(sk, skb)) kfree_skb(skb); @@ -123,7 +123,7 @@ msg->msg_flags |= MSG_TRUNC; copied = len; } - err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto out_free_skb; diff -u --recursive --new-file v2.4.3/linux/net/ipv6/exthdrs.c linux/net/ipv6/exthdrs.c --- v2.4.3/linux/net/ipv6/exthdrs.c Sat Jan 8 21:36:21 2000 +++ linux/net/ipv6/exthdrs.c Thu Apr 12 12:11:39 2001 @@ -7,7 +7,7 @@ * Andi Kleen <ak@muc.de> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: exthdrs.c,v 1.10 2000/01/09 02:19:55 davem Exp $ + * $Id: exthdrs.c,v 1.12 2001/01/22 02:36:37 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* Changes: + * yoshfuji : ensure not to overrun while parsing + * tlv options. + */ + #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> @@ -41,15 +46,15 @@ /* * Parsing inbound headers. * - * Parsing function "func" returns pointer to the place, + * Parsing function "func" returns offset wrt skb->nh of the place, * where next nexthdr value is stored or NULL, if parsing - * failed. It should also update skb->h. + * failed. It should also update skb->h tp point at the next header. */ struct hdrtype_proc { int type; - u8* (*func) (struct sk_buff **, u8 *ptr); + int (*func) (struct sk_buff **, int offset); }; /* @@ -63,7 +68,7 @@ struct tlvtype_proc { int type; - int (*func) (struct sk_buff *, __u8 *ptr); + int (*func) (struct sk_buff *, int offset); }; /********************* @@ -72,12 +77,12 @@ /* An unknown option is detected, decide what to do */ -int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt) +int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) { - switch ((opt[0] & 0xC0) >> 6) { + switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { case 0: /* ignore */ return 1; - + case 1: /* drop packet */ break; @@ -88,7 +93,7 @@ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) break; case 2: /* send ICMP PARM PROB regardless and drop packet */ - icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, opt); + icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff); return 0; }; @@ -98,24 +103,21 @@ /* Parse tlv encoded option header (hop-by-hop or destination) */ -static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb, - __u8 *nhptr) +static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) { struct tlvtype_proc *curr; - u8 *ptr = skb->h.raw; - int len = ((ptr[1]+1)<<3) - 2; + int off = skb->h.raw - skb->nh.raw; + int len = ((skb->h.raw[1]+1)<<3); - ptr += 2; + if ((skb->h.raw + len) - skb->data > skb_headlen(skb)) + goto bad; - if (skb->tail - (ptr + len) < 0) { - kfree_skb(skb); - return 0; - } + len -= 2; while (len > 0) { - int optlen = ptr[1]+2; + int optlen = skb->nh.raw[off+1]+2; - switch (ptr[0]) { + switch (skb->nh.raw[off]) { case IPV6_TLV_PAD0: optlen = 1; break; @@ -124,24 +126,30 @@ break; default: /* Other TLV code so scan list */ + if (optlen > len) + goto bad; for (curr=procs; curr->type >= 0; curr++) { - if (curr->type == ptr[0]) { - if (curr->func(skb, ptr) == 0) + if (curr->type == skb->nh.raw[off]) { + /* type specific length/alignment + checks will be perfomed in the + func(). */ + if (curr->func(skb, off) == 0) return 0; break; } } if (curr->type < 0) { - if (ip6_tlvopt_unknown(skb, ptr) == 0) + if (ip6_tlvopt_unknown(skb, off) == 0) return 0; } break; } - ptr += optlen; + off += optlen; len -= optlen; } if (len == 0) return 1; +bad: kfree_skb(skb); return 0; } @@ -155,37 +163,42 @@ {-1, NULL} }; -static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff) { struct sk_buff *skb=*skb_ptr; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; - struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw; - opt->dst1 = (u8*)hdr - skb->nh.raw; + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || + !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { + kfree_skb(skb); + return -1; + } + + opt->dst1 = skb->h.raw - skb->nh.raw; - if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) { - skb->h.raw += ((hdr->hdrlen+1)<<3); - return &hdr->nexthdr; + if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { + skb->h.raw += ((skb->h.raw[1]+1)<<3); + return opt->dst1; } - return NULL; + return -1; } /******************************** NONE header. No data in packet. ********************************/ -static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff) { kfree_skb(*skb_ptr); - return NULL; + return -1; } /******************************** Routing header. ********************************/ -static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) { struct sk_buff *skb = *skb_ptr; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; @@ -194,36 +207,38 @@ int addr_type; int n, i; - struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw; + struct ipv6_rt_hdr *hdr; struct rt0_hdr *rthdr; - if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) { + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || + !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { IP6_INC_STATS_BH(Ip6InHdrErrors); kfree_skb(skb); - return NULL; + return -1; + } + + hdr = (struct ipv6_rt_hdr *) skb->h.raw; + + if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) || + skb->pkt_type != PACKET_HOST) { + kfree_skb(skb); + return -1; } looped_back: if (hdr->segments_left == 0) { - opt->srcrt = (u8*)hdr - skb->nh.raw; + opt->srcrt = skb->h.raw - skb->nh.raw; skb->h.raw += (hdr->hdrlen + 1) << 3; opt->dst0 = opt->dst1; opt->dst1 = 0; - return &hdr->nexthdr; + return (&hdr->nexthdr) - skb->nh.raw; } - if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) { - u8 *pos = (u8*) hdr; - - if (hdr->type != IPV6_SRCRT_TYPE_0) - pos += 2; - else - pos += 1; - - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos); - return NULL; + if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1); + return -1; } - + /* * This is the routing header forwarding algorithm from * RFC 1883, page 17. @@ -232,8 +247,8 @@ n = hdr->hdrlen >> 1; if (hdr->segments_left > n) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left); - return NULL; + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw); + return -1; } /* We are about to mangle packet header. Be careful! @@ -243,12 +258,15 @@ struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); kfree_skb(skb); if (skb2 == NULL) - return NULL; + return -1; *skb_ptr = skb = skb2; opt = (struct inet6_skb_parm *)skb2->cb; hdr = (struct ipv6_rt_hdr *) skb2->h.raw; } + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + i = n - --hdr->segments_left; rthdr = (struct rt0_hdr *) hdr; @@ -257,9 +275,9 @@ addr_type = ipv6_addr_type(addr); - if (addr_type == IPV6_ADDR_MULTICAST) { + if (addr_type&IPV6_ADDR_MULTICAST) { kfree_skb(skb); - return NULL; + return -1; } ipv6_addr_copy(&daddr, addr); @@ -270,21 +288,21 @@ ip6_route_input(skb); if (skb->dst->error) { skb->dst->input(skb); - return NULL; + return -1; } if (skb->dst->dev->flags&IFF_LOOPBACK) { if (skb->nh.ipv6h->hop_limit <= 1) { icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0, skb->dev); kfree_skb(skb); - return NULL; + return -1; } skb->nh.ipv6h->hop_limit--; goto looped_back; } skb->dst->input(skb); - return NULL; + return -1; } /* @@ -374,20 +392,30 @@ and opt->hdrlen is even. Shit! --ANK (980730) */ -static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr) +static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff) { struct sk_buff *skb=*skb_ptr; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; - struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw; - int len = (hdr->hdrlen+2)<<2; + int len; + + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8)) + goto fail; + + len = (skb->h.raw[1]+1)<<2; if (len&7) - return NULL; - opt->auth = (u8*)hdr - skb->nh.raw; - if (skb->h.raw + len > skb->tail) - return NULL; + goto fail; + + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len)) + goto fail; + + opt->auth = skb->h.raw - skb->nh.raw; skb->h.raw += len; - return &hdr->nexthdr; + return opt->auth; + +fail: + kfree_skb(skb); + return -1; } /* This list MUST NOT contain entry for NEXTHDR_HOP. @@ -408,22 +436,22 @@ {-1, NULL} }; -u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr) +int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff) { struct hdrtype_proc *hdrt; - u8 nexthdr = *nhptr; + u8 nexthdr = (*skb_in)->nh.raw[nhoff]; restart: for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) { if (hdrt->type == nexthdr) { - if ((nhptr = hdrt->func(skb_in, nhptr)) != NULL) { - nexthdr = *nhptr; + if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) { + nexthdr = (*skb_in)->nh.raw[nhoff]; goto restart; } - return NULL; + return -1; } } - return nhptr; + return nhoff; } @@ -433,37 +461,37 @@ /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */ -static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr) +static int ipv6_hop_ra(struct sk_buff *skb, int optoff) { - if (ptr[1] == 2) { - ((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw; + if (skb->nh.raw[optoff+1] == 2) { + ((struct inet6_skb_parm*)skb->cb)->ra = optoff; return 1; } if (net_ratelimit()) - printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", ptr[1]); + printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]); kfree_skb(skb); return 0; } /* Jumbo payload */ -static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr) +static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) { u32 pkt_len; - if (ptr[1] != 4 || ((ptr-skb->nh.raw)&3) != 2) { + if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { if (net_ratelimit()) - printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", ptr[1]); + printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]); goto drop; } - pkt_len = ntohl(*(u32*)(ptr+2)); + pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2)); if (pkt_len < 0x10000) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr+2); + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); return 0; } if (skb->nh.ipv6h->payload_len) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr); + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); return 0; } @@ -471,7 +499,11 @@ IP6_INC_STATS_BH(Ip6InTruncatedPkts); goto drop; } - skb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); + if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { + __pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + } return 1; drop: @@ -485,12 +517,12 @@ {-1, NULL} }; -u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr) +int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) { ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr); - if (ip6_parse_tlv(tlvprochopopt_lst, skb, nhptr)) - return nhptr+((nhptr[1]+1)<<3); - return NULL; + if (ip6_parse_tlv(tlvprochopopt_lst, skb)) + return sizeof(struct ipv6hdr); + return -1; } /* @@ -684,7 +716,7 @@ * find out if nexthdr is a well-known extension header or a protocol */ -static __inline__ int ipv6_ext_hdr(u8 nexthdr) +int ipv6_ext_hdr(u8 nexthdr) { /* * find out if nexthdr is an extension header or a protocol @@ -739,33 +771,36 @@ * --ANK (980726) */ -u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len) +int ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len) { u8 nexthdr = *nexthdrp; while (ipv6_ext_hdr(nexthdr)) { - int hdrlen; + struct ipv6_opt_hdr hdr; + int hdrlen; - if (len < sizeof(struct ipv6_opt_hdr)) - return NULL; + if (len < (int)sizeof(struct ipv6_opt_hdr)) + return -1; if (nexthdr == NEXTHDR_NONE) - return NULL; + return -1; + if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) + BUG(); if (nexthdr == NEXTHDR_FRAGMENT) { - struct frag_hdr *fhdr = (struct frag_hdr *) hdr; + struct frag_hdr *fhdr = (struct frag_hdr *) &hdr; if (ntohs(fhdr->frag_off) & ~0x7) break; hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hdr.hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(&hdr); - nexthdr = hdr->nexthdr; - hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen); + nexthdr = hdr.nexthdr; len -= hdrlen; + start += hdrlen; } *nexthdrp = nexthdr; - return (u8*)hdr; + return start; } diff -u --recursive --new-file v2.4.3/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c --- v2.4.3/linux/net/ipv6/icmp.c Mon Jan 1 11:01:58 2001 +++ linux/net/ipv6/icmp.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.28 2000/03/25 01:55:20 davem Exp $ + * $Id: icmp.c,v 1.31 2001/01/22 02:36:37 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -23,6 +23,8 @@ * Andi Kleen : exception handling * Andi Kleen add rate limits. never reply to a icmp. * add more length checks and other fixes. + * yoshfuji : ensure to sent parameter problem for + * fragments. */ #define __NO_VERSION__ @@ -66,7 +68,7 @@ struct socket *icmpv6_socket; -int icmpv6_rcv(struct sk_buff *skb, unsigned long len); +int icmpv6_rcv(struct sk_buff *skb); static struct inet6_protocol icmpv6_protocol = { @@ -81,7 +83,8 @@ struct icmpv6_msg { struct icmp6hdr icmph; - __u8 *data; + struct sk_buff *skb; + int offset; struct in6_addr *daddr; int len; __u32 csum; @@ -136,19 +139,10 @@ struct icmp6hdr *icmph; __u32 csum; - /* - * in theory offset must be 0 since we never send more - * than IPV6_MIN_MTU bytes on an error or more than the path mtu - * on an echo reply. (those are the rules on RFC 1883) - * - * Luckily, this statement is obsolete after - * draft-ietf-ipngwg-icmp-v2-00 --ANK (980730) - */ - if (offset) { - csum = csum_partial_copy_nocheck((void *) msg->data + - offset - sizeof(struct icmp6hdr), - buff, len, msg->csum); + csum = skb_copy_and_csum_bits(msg->skb, msg->offset + + (offset - sizeof(struct icmp6hdr)), + buff, len, msg->csum); msg->csum = csum; return 0; } @@ -156,9 +150,9 @@ csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff, sizeof(struct icmp6hdr), msg->csum); - csum = csum_partial_copy_nocheck((void *) msg->data, - buff + sizeof(struct icmp6hdr), - len - sizeof(struct icmp6hdr), csum); + csum = skb_copy_and_csum_bits(msg->skb, msg->offset, + buff + sizeof(struct icmp6hdr), + len - sizeof(struct icmp6hdr), csum); icmph = (struct icmp6hdr *) buff; @@ -171,11 +165,9 @@ /* * Slightly more convenient version of icmpv6_send. */ -void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos) +void icmpv6_param_prob(struct sk_buff *skb, int code, int pos) { - int offset = (u8*)pos - (u8*)skb->nh.ipv6h; - - icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev); + icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); kfree_skb(skb); } @@ -186,29 +178,30 @@ * - it was icmp error message. * - it is truncated, so that it is known, that protocol is ICMPV6 * (i.e. in the middle of some exthdr) - * - it is not the first fragment. BTW IPv6 specs say nothing about - * this case, but it is clear, that our reply would be useless - * for sender. * * --ANK (980726) */ -static int is_ineligible(struct ipv6hdr *hdr, int len) +static int is_ineligible(struct sk_buff *skb) { - u8 *ptr; - __u8 nexthdr = hdr->nexthdr; + int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data; + int len = skb->len - ptr; + __u8 nexthdr = skb->nh.ipv6h->nexthdr; - if (len < (int)sizeof(*hdr)) + if (len < 0) return 1; - ptr = ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len - sizeof(*hdr)); - if (!ptr) + ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len); + if (ptr < 0) return 0; if (nexthdr == IPPROTO_ICMPV6) { - struct icmp6hdr *ihdr = (struct icmp6hdr *)ptr; - return (ptr - (u8*)hdr) > len || !(ihdr->icmp6_type & 0x80); + u8 type; + if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type), + &type, 1) + || !(type & 0x80)) + return 1; } - return nexthdr == NEXTHDR_FRAGMENT; + return 0; } int sysctl_icmpv6_time = 1*HZ; @@ -263,9 +256,12 @@ static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset) { - u8 *buff = skb->nh.raw; + u8 optval; - return ( ( *(buff + offset) & 0xC0 ) == 0x80 ); + offset += skb->nh.raw - skb->data; + if (skb_copy_bits(skb, offset, &optval, 1)) + return 1; + return (optval&0xC0) == 0x80; } /* @@ -284,15 +280,8 @@ int addr_type = 0; int len; - /* - * sanity check pointer in case of parameter problem - */ - - if (type == ICMPV6_PARAMPROB && - (info > (skb->tail - ((unsigned char *) hdr)))) { - printk(KERN_DEBUG "icmpv6_send: bug! pointer > skb\n"); + if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) return; - } /* * Make sure we respect the rules @@ -300,7 +289,6 @@ * Rule (e.1) is enforced by not using icmpv6_send * in any code that processes icmp errors. */ - addr_type = ipv6_addr_type(&hdr->daddr); if (ipv6_chk_addr(&hdr->daddr, skb->dev)) @@ -341,9 +329,9 @@ /* * Never answer to a ICMP packet. */ - if (is_ineligible(hdr, (u8*)skb->tail - (u8*)hdr)) { + if (is_ineligible(skb)) { if (net_ratelimit()) - printk(KERN_DEBUG "icmpv6_send: no reply to icmp error/fragment\n"); + printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); return; } @@ -371,12 +359,13 @@ msg.icmph.icmp6_cksum = 0; msg.icmph.icmp6_pointer = htonl(info); - msg.data = skb->nh.raw; + msg.skb = skb; + msg.offset = skb->nh.raw - skb->data; msg.csum = 0; msg.daddr = &hdr->saddr; - len = min((skb->tail - ((unsigned char *) hdr)) + sizeof(struct icmp6hdr), - IPV6_MIN_MTU - sizeof(struct ipv6hdr)); + len = skb->len - msg.offset + sizeof(struct icmp6hdr); + len = min(len, IPV6_MIN_MTU - sizeof(struct ipv6hdr)); if (len < 0) { printk(KERN_DEBUG "icmp: len problem\n"); @@ -397,37 +386,30 @@ static void icmpv6_echo_reply(struct sk_buff *skb) { struct sock *sk = icmpv6_socket->sk; - struct ipv6hdr *hdr = skb->nh.ipv6h; struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw; struct in6_addr *saddr; struct icmpv6_msg msg; struct flowi fl; - unsigned char *data; - int len; - - data = (char *) (icmph + 1); - saddr = &hdr->daddr; + saddr = &skb->nh.ipv6h->daddr; if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST) saddr = NULL; - len = skb->tail - data; - len += sizeof(struct icmp6hdr); - msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY; msg.icmph.icmp6_code = 0; msg.icmph.icmp6_cksum = 0; msg.icmph.icmp6_identifier = icmph->icmp6_identifier; msg.icmph.icmp6_sequence = icmph->icmp6_sequence; - msg.data = data; + msg.skb = skb; + msg.offset = 0; msg.csum = 0; - msg.len = len; - msg.daddr = &hdr->saddr; + msg.len = skb->len + sizeof(struct icmp6hdr); + msg.daddr = &skb->nh.ipv6h->saddr; fl.proto = IPPROTO_ICMPV6; - fl.nl_u.ip6_u.daddr = &hdr->saddr; + fl.nl_u.ip6_u.daddr = msg.daddr; fl.nl_u.ip6_u.saddr = saddr; fl.oif = skb->dev->ifindex; fl.fl6_flowlabel = 0; @@ -437,7 +419,7 @@ if (icmpv6_xmit_lock_bh()) return; - ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, + ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1, MSG_DONTWAIT); ICMP6_INC_STATS_BH(Icmp6OutEchoReplies); ICMP6_INC_STATS_BH(Icmp6OutMsgs); @@ -445,29 +427,35 @@ icmpv6_xmit_unlock_bh(); } -static void icmpv6_notify(struct sk_buff *skb, - int type, int code, u32 info, unsigned char *buff, int len) +static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) { - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; - struct ipv6hdr *hdr = (struct ipv6hdr *) buff; + struct in6_addr *saddr, *daddr; struct inet6_protocol *ipprot; struct sock *sk; - u8 *pb; + int inner_offset; int hash; u8 nexthdr; - nexthdr = hdr->nexthdr; - - len -= sizeof(struct ipv6hdr); - if (len < 0) + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) return; - /* now skip over extension headers */ - pb = ipv6_skip_exthdr((struct ipv6_opt_hdr *) (hdr + 1), &nexthdr, len); - if (!pb) + nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; + if (ipv6_ext_hdr(nexthdr)) { + /* now skip over extension headers */ + inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr)); + if (inner_offset<0) + return; + } else { + inner_offset = sizeof(struct ipv6hdr); + } + + /* Checkin header including 8 bytes of inner protocol header. */ + if (!pskb_may_pull(skb, inner_offset+8)) return; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. Without this we will not able f.e. to make source routed pmtu discovery. @@ -484,13 +472,13 @@ continue; if (ipprot->err_handler) - ipprot->err_handler(skb, hdr, NULL, type, code, pb, info); + ipprot->err_handler(skb, NULL, type, code, inner_offset, info); } read_lock(&raw_v6_lock); if ((sk = raw_v6_htable[hash]) != NULL) { while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { - rawv6_err(sk, skb, hdr, NULL, type, code, pb, info); + rawv6_err(sk, skb, NULL, type, code, inner_offset, info); sk = sk->next; } } @@ -501,28 +489,31 @@ * Handle icmp messages */ -int icmpv6_rcv(struct sk_buff *skb, unsigned long len) +int icmpv6_rcv(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; + struct in6_addr *saddr, *daddr; struct ipv6hdr *orig_hdr; - struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw; - int ulen; + struct icmp6hdr *hdr; int type; ICMP6_INC_STATS_BH(Icmp6InMsgs); - if (len < sizeof(struct icmp6hdr)) - goto discard_it; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; /* Perform checksum. */ - switch (skb->ip_summed) { - case CHECKSUM_NONE: - skb->csum = csum_partial((char *)hdr, len, 0); - case CHECKSUM_HW: - if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, + if (skb->ip_summed == CHECKSUM_HW) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, skb->csum)) { + printk(KERN_DEBUG "ICMPv6 hw checksum failed\n"); + skb->ip_summed = CHECKSUM_NONE; + } + } + if (skb->ip_summed == CHECKSUM_NONE) { + if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, + skb_checksum(skb, 0, skb->len, 0))) { printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", ntohs(saddr->in6_u.u6_addr16[0]), ntohs(saddr->in6_u.u6_addr16[1]), @@ -542,14 +533,12 @@ ntohs(daddr->in6_u.u6_addr16[7])); goto discard_it; } - default:; - /* CHECKSUM_UNNECESSARY */ - }; + } - /* - * length of original packet carried in skb - */ - ulen = skb->tail - (unsigned char *) (hdr + 1); + if (!pskb_pull(skb, sizeof(struct icmp6hdr))) + goto discard_it; + + hdr = (struct icmp6hdr *) skb->h.raw; type = hdr->icmp6_type; @@ -559,7 +548,6 @@ (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; switch (type) { - case ICMPV6_ECHO_REQUEST: icmpv6_echo_reply(skb); break; @@ -574,10 +562,12 @@ destination cache will allow to solve this problem --ANK (980726) */ + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto discard_it; + hdr = (struct icmp6hdr *) skb->data; orig_hdr = (struct ipv6hdr *) (hdr + 1); - if (ulen >= sizeof(struct ipv6hdr)) - rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev, - ntohl(hdr->icmp6_mtu)); + rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev, + ntohl(hdr->icmp6_mtu)); /* * Drop through to notify @@ -586,8 +576,7 @@ case ICMPV6_DEST_UNREACH: case ICMPV6_TIME_EXCEED: case ICMPV6_PARAMPROB: - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu, - (char *) (hdr + 1), ulen); + icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); break; case NDISC_ROUTER_SOLICITATION: @@ -595,15 +584,21 @@ case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_REDIRECT: - ndisc_rcv(skb, len); + if (skb_is_nonlinear(skb) && + skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return 0; + } + + ndisc_rcv(skb); break; case ICMPV6_MGM_QUERY: - igmp6_event_query(skb, hdr, len); + igmp6_event_query(skb); break; case ICMPV6_MGM_REPORT: - igmp6_event_report(skb, hdr, len); + igmp6_event_report(skb); break; case ICMPV6_MGM_REDUCTION: @@ -612,7 +607,7 @@ default: if (net_ratelimit()) printk(KERN_DEBUG "icmpv6: msg of unkown type\n"); - + /* informational */ if (type & 0x80) break; @@ -622,8 +617,7 @@ * must pass to upper level */ - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu, - (char *) (hdr + 1), ulen); + icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); }; kfree_skb(skb); return 0; diff -u --recursive --new-file v2.4.3/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c --- v2.4.3/linux/net/ipv6/ip6_input.c Mon Dec 11 12:37:04 2000 +++ linux/net/ipv6/ip6_input.c Thu Apr 12 12:11:39 2001 @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.18 2000/12/08 17:15:54 davem Exp $ + * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -44,7 +44,6 @@ static inline int ip6_rcv_finish( struct sk_buff *skb) { - if (skb->dst == NULL) ip6_route_input(skb); @@ -69,9 +68,15 @@ */ ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex; + if (skb->len < sizeof(struct ipv6hdr)) + goto err; + + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + hdr = skb->nh.ipv6h; - if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6) + if (hdr->version != 6) goto err; pkt_len = ntohs(hdr->payload_len); @@ -80,16 +85,24 @@ if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { if (pkt_len + sizeof(struct ipv6hdr) > skb->len) goto truncated; - skb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); + if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { + if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr))) + goto drop; + hdr = skb->nh.ipv6h; + if (skb->ip_summed == CHECKSUM_HW) + skb->ip_summed = CHECKSUM_NONE; + } } if (hdr->nexthdr == NEXTHDR_HOP) { skb->h.raw = (u8*)(hdr+1); - if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) { + if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) { IP6_INC_STATS_BH(Ip6InHdrErrors); return 0; } + hdr = skb->nh.ipv6h; } + return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); truncated: IP6_INC_STATS_BH(Ip6InTruncatedPkts); @@ -111,12 +124,11 @@ struct ipv6hdr *hdr = skb->nh.ipv6h; struct inet6_protocol *ipprot; struct sock *raw_sk; - __u8 *nhptr; + int nhoff; int nexthdr; int found = 0; u8 hash; - int len; - + skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr); /* @@ -124,13 +136,13 @@ */ nexthdr = hdr->nexthdr; - nhptr = &hdr->nexthdr; + nhoff = offsetof(struct ipv6hdr, nexthdr); /* Skip hop-by-hop options, they are already parsed. */ if (nexthdr == NEXTHDR_HOP) { - nhptr = (u8*)(hdr+1); - nexthdr = *nhptr; - skb->h.raw += (nhptr[1]+1)<<3; + nhoff = sizeof(struct ipv6hdr); + nexthdr = skb->h.raw[0]; + skb->h.raw += (skb->h.raw[1]+1)<<3; } /* This check is sort of optimization. @@ -138,17 +150,23 @@ which are missing with probability of 200% */ if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) { - nhptr = ipv6_parse_exthdrs(&skb, nhptr); - if (nhptr == NULL) + nhoff = ipv6_parse_exthdrs(&skb, nhoff); + if (nhoff < 0) return 0; - nexthdr = *nhptr; + nexthdr = skb->nh.raw[nhoff]; hdr = skb->nh.ipv6h; } - len = skb->tail - skb->h.raw; + + if (!pskb_pull(skb, skb->h.raw - skb->data)) + goto discard; + + if (skb->ip_summed == CHECKSUM_HW) + skb->csum = csum_sub(skb->csum, + csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0)); raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)]; if (raw_sk) - raw_sk = ipv6_raw_deliver(skb, nexthdr, len); + raw_sk = ipv6_raw_deliver(skb, nexthdr); hash = nexthdr & (MAX_INET_PROTOS - 1); for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; @@ -163,12 +181,12 @@ buff = skb_clone(skb, GFP_ATOMIC); if (buff) - ipprot->handler(buff, len); + ipprot->handler(buff); found = 1; } if (raw_sk) { - rawv6_rcv(raw_sk, skb, len); + rawv6_rcv(raw_sk, skb); sock_put(raw_sk); found = 1; } @@ -178,9 +196,13 @@ */ if (!found) { IP6_INC_STATS_BH(Ip6InUnknownProtos); - icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr); + icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff); } + return 0; + +discard: + kfree_skb(skb); return 0; } diff -u --recursive --new-file v2.4.3/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c --- v2.4.3/linux/net/ipv6/ip6_output.c Thu Jun 22 07:23:26 2000 +++ linux/net/ipv6/ip6_output.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.27 2000/06/21 17:18:40 davem Exp $ + * $Id: ip6_output.c,v 1.30 2001/03/03 01:20:10 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -85,7 +85,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) { newskb->mac.raw = newskb->data; - skb_pull(newskb, newskb->nh.raw - newskb->data); + __skb_pull(newskb, newskb->nh.raw - newskb->data); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; BUG_TRAP(newskb->dst); @@ -113,7 +113,7 @@ is not supported in any case. */ if (newskb) - NF_HOOK(PF_INET, NF_IP6_POST_ROUTING, newskb, NULL, + NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, newskb, NULL, newskb->dev, ip6_dev_loopback_xmit); @@ -405,7 +405,7 @@ last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len + dst->dev->hard_header_len + 15, - 0, flags & MSG_DONTWAIT, &err); + flags & MSG_DONTWAIT, &err); if (last_skb == NULL) return err; @@ -624,7 +624,7 @@ goto out; skb = sock_alloc_send_skb(sk, pktlength + 15 + - dev->hard_header_len, 0, + dev->hard_header_len, flags & MSG_DONTWAIT, &err); if (skb == NULL) { @@ -697,14 +697,14 @@ if (last) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) - rawv6_rcv(last, skb2, skb2->len); + rawv6_rcv(last, skb2); } last = sk; } } if (last) { - rawv6_rcv(last, skb, skb->len); + rawv6_rcv(last, skb); read_unlock(&ip6_ra_lock); return 1; } @@ -724,7 +724,9 @@ struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb; if (ipv6_devconf.forwarding == 0 && opt->srcrt == 0) - goto drop; + goto error; + + skb->ip_summed = CHECKSUM_NONE; /* * We DO NOT make any processing on @@ -785,7 +787,7 @@ } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK |IPV6_ADDR_LINKLOCAL)) { /* This check is security critical. */ - goto drop; + goto error; } if (skb->len > dst->pmtu) { @@ -797,8 +799,8 @@ return -EMSGSIZE; } - if ((skb = skb_cow(skb, dst->dev->hard_header_len)) == NULL) - return 0; + if (skb_cow(skb, dst->dev->hard_header_len)) + goto drop; hdr = skb->nh.ipv6h; @@ -809,8 +811,9 @@ IP6_INC_STATS_BH(Ip6OutForwDatagrams); return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); -drop: +error: IP6_INC_STATS_BH(Ip6InAddrErrors); +drop: kfree_skb(skb); return -EINVAL; } diff -u --recursive --new-file v2.4.3/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c --- v2.4.3/linux/net/ipv6/mcast.c Mon Sep 18 15:04:13 2000 +++ linux/net/ipv6/mcast.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.33 2000/09/18 05:59:48 davem Exp $ + * $Id: mcast.c,v 1.36 2001/03/03 01:20:10 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* Changes: + * + * yoshfuji : fix format of router-alert option + */ + #define __NO_VERSION__ #include <linux/config.h> #include <linux/module.h> @@ -392,17 +397,19 @@ spin_unlock(&ma->mca_lock); } -int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len) +int igmp6_event_query(struct sk_buff *skb) { struct ifmcaddr6 *ma; struct in6_addr *addrp; unsigned long resptime; struct inet6_dev *idev; + struct icmp6hdr *hdr; - - if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr)) + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; + hdr = (struct icmp6hdr*) skb->h.raw; + /* Drop queries with not link local source */ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL)) return -EINVAL; @@ -437,19 +444,22 @@ } -int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len) +int igmp6_event_report(struct sk_buff *skb) { struct ifmcaddr6 *ma; struct in6_addr *addrp; struct inet6_dev *idev; + struct icmp6hdr *hdr; /* Our own report looped back. Ignore it. */ if (skb->pkt_type == PACKET_LOOPBACK) return 0; - if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr)) + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; + hdr = (struct icmp6hdr*) skb->h.raw; + /* Drop reports with not link local source */ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL)) return -EINVAL; @@ -491,7 +501,7 @@ struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, - IPV6_TLV_ROUTERALERT, 0, 0, 0, + IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; snd_addr = addr; @@ -504,7 +514,7 @@ payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; - skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err); + skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err); if (skb == NULL) return; diff -u --recursive --new-file v2.4.3/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.4.3/linux/net/ipv6/ndisc.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv6/ndisc.c Thu Apr 12 12:11:39 2001 @@ -338,7 +338,7 @@ } skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (skb == NULL) { ND_PRINTK1("send_na: alloc skb failed\n"); @@ -397,7 +397,7 @@ len += NDISC_OPT_SPACE(dev->addr_len); skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (skb == NULL) { ND_PRINTK1("send_ns: alloc skb failed\n"); return; @@ -458,7 +458,7 @@ len += NDISC_OPT_SPACE(dev->addr_len); skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (skb == NULL) { ND_PRINTK1("send_ns: alloc skb failed\n"); return; @@ -869,7 +869,7 @@ } buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15, - 0, 0, &err); + 0, &err); if (buff == NULL) { ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n"); return; @@ -957,11 +957,11 @@ static void pndisc_redo(struct sk_buff *skb) { - ndisc_rcv(skb, skb->len); + ndisc_rcv(skb); kfree_skb(skb); } -int ndisc_rcv(struct sk_buff *skb, unsigned long len) +int ndisc_rcv(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct in6_addr *saddr = &skb->nh.ipv6h->saddr; @@ -969,6 +969,8 @@ struct nd_msg *msg = (struct nd_msg *) skb->h.raw; struct neighbour *neigh; struct inet6_ifaddr *ifp; + + __skb_push(skb, skb->data-skb->h.raw); switch (msg->icmph.icmp6_type) { case NDISC_NEIGHBOUR_SOLICITATION: diff -u --recursive --new-file v2.4.3/linux/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.4.3/linux/net/ipv6/raw.c Fri Feb 9 11:29:44 2001 +++ linux/net/ipv6/raw.c Thu Apr 12 12:11:39 2001 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.42 2000/11/28 13:38:38 davem Exp $ + * $Id: raw.c,v 1.45 2001/02/18 09:10:42 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -116,8 +116,11 @@ struct raw6_opt *opt; opt = &sk->tp_pinfo.tp_raw; - icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1); - return test_bit(icmph->icmp6_type, &opt->filter); + if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) { + icmph = (struct icmp6hdr *) skb->data; + return test_bit(icmph->icmp6_type, &opt->filter); + } + return 0; } /* @@ -125,8 +128,7 @@ * (should consider queueing the skb in the sock receive_queue * without calling rawv6.c) */ -struct sock * ipv6_raw_deliver(struct sk_buff *skb, - int nexthdr, unsigned long len) +struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { struct in6_addr *saddr; struct in6_addr *daddr; @@ -163,7 +165,7 @@ buff = skb_clone(skb, GFP_ATOMIC); if (buff) - rawv6_rcv(sk2, buff, len); + rawv6_rcv(sk2, buff); } } @@ -177,8 +179,6 @@ return sk; } - - /* This cleans up af_inet6 a bit. -DaveM */ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -239,16 +239,13 @@ return err; } -void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr, +void rawv6_err(struct sock *sk, struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, unsigned char *buff, u32 info) + int type, int code, int offset, u32 info) { int err; int harderr; - if (buff > skb->tail) - return; - /* Report error on raw socket, if: 1. User requested recverr. 2. Socket is connected (otherwise the error indication @@ -261,8 +258,12 @@ if (type == ICMPV6_PKT_TOOBIG) harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO); - if (sk->net_pinfo.af_inet6.recverr) - ipv6_icmp_error(sk, skb, err, 0, ntohl(info), buff); + if (sk->net_pinfo.af_inet6.recverr) { + u8 *payload = skb->data; + if (!sk->protinfo.af_inet.hdrincl) + payload += offset; + ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload); + } if (sk->net_pinfo.af_inet6.recverr || harderr) { sk->err = err; @@ -290,10 +291,12 @@ * maybe we could have the network decide uppon a hint if it * should call raw_rcv for demultiplexing */ -int rawv6_rcv(struct sock *sk, struct sk_buff *skb, unsigned long len) +int rawv6_rcv(struct sock *sk, struct sk_buff *skb) { - if (sk->protinfo.af_inet.hdrincl) + if (sk->protinfo.af_inet.hdrincl) { + __skb_push(skb, skb->nh.raw - skb->data); skb->h.raw = skb->nh.raw; + } rawv6_rcv_skb(sk, skb); return 0; @@ -325,7 +328,7 @@ if (!skb) goto out; - copied = skb->tail - skb->h.raw; + copied = skb->len; if (copied > len) { copied = len; msg->msg_flags |= MSG_TRUNC; @@ -594,6 +597,8 @@ case ICMPV6_FILTER: if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; if (len > sizeof(struct icmp6_filter)) len = sizeof(struct icmp6_filter); if (put_user(len, optlen)) diff -u --recursive --new-file v2.4.3/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c --- v2.4.3/linux/net/ipv6/reassembly.c Sun Mar 25 18:14:25 2001 +++ linux/net/ipv6/reassembly.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: reassembly.c,v 1.22 2000/12/08 17:41:54 davem Exp $ + * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $ * * Based on: net/ipv4/ip_fragment.c * @@ -79,11 +79,12 @@ int len; int meat; int iif; + struct timeval stamp; + unsigned int csum; __u8 last_in; /* has first/last segment arrived? */ #define COMPLETE 4 #define FIRST_IN 2 #define LAST_IN 1 - __u8 nexthdr; __u16 nhoffset; struct frag_queue **pprev; }; @@ -349,7 +350,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr, u8 *nhptr) + struct frag_hdr *fhdr, int nhoff) { struct sk_buff *prev, *next; int offset, end; @@ -362,10 +363,14 @@ ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); if ((unsigned int)end >= 65536) { - icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off); - goto err; + icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw); + return; } + if (skb->ip_summed == CHECKSUM_HW) + skb->csum = csum_sub(skb->csum, + csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); + /* Is this the final fragment? */ if (!(fhdr->frag_off & __constant_htons(0x0001))) { /* If we already have some bits beyond end @@ -381,16 +386,12 @@ * Required by the RFC. */ if (end & 0x7) { - printk(KERN_DEBUG "fragment not rounded to 8bytes\n"); - - /* - It is not in specs, but I see no reasons - to send an error in this case. --ANK + /* RFC2460 says always send parameter problem in + * this case. -DaveM */ - if (offset == 0) - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - &skb->nh.ipv6h->payload_len); - goto err; + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, + offsetof(struct ipv6hdr, payload_len)); + return; } if (end > fq->len) { /* Some bits beyond end -> corruption. */ @@ -404,8 +405,14 @@ goto err; /* Point into the IP datagram 'data' part. */ - skb_pull(skb, (u8 *) (fhdr + 1) - skb->data); - skb_trim(skb, end - offset); + if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) + goto err; + if (end-offset < skb->len) { + if (pskb_trim(skb, end - offset)) + goto err; + if (skb->ip_summed != CHECKSUM_UNNECESSARY) + skb->ip_summed = CHECKSUM_NONE; + } /* Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put @@ -429,7 +436,10 @@ offset += i; if (end <= offset) goto err; - skb_pull(skb, i); + if (!pskb_pull(skb, i)) + goto err; + if (skb->ip_summed != CHECKSUM_UNNECESSARY) + skb->ip_summed = CHECKSUM_NONE; } } @@ -443,9 +453,12 @@ /* Eat head of the next overlapped fragment * and leave the loop. The next ones cannot overlap. */ + if (!pskb_pull(next, i)) + goto err; FRAG6_CB(next)->offset += i; /* next fragment */ - skb_pull(next, i); fq->meat -= i; + if (next->ip_summed != CHECKSUM_UNNECESSARY) + next->ip_summed = CHECKSUM_NONE; break; } else { struct sk_buff *free_it = next; @@ -474,20 +487,18 @@ else fq->fragments = skb; - fq->iif = skb->dev->ifindex; + if (skb->dev) + fq->iif = skb->dev->ifindex; skb->dev = NULL; + fq->stamp = skb->stamp; fq->meat += skb->len; atomic_add(skb->truesize, &ip6_frag_mem); - /* First fragment. - nexthdr and nhptr are get from the first fragment. - Moreover, nexthdr is UNDEFINED for all the fragments but the - first one. - (fixed --ANK (980728)) + /* The first fragment. + * nhoffset is obtained from the first fragment, of course. */ if (offset == 0) { - fq->nexthdr = fhdr->nexthdr; - fq->nhoffset = nhptr - skb->nh.raw; + fq->nhoffset = nhoff; fq->last_in |= FIRST_IN; } return; @@ -505,21 +516,13 @@ * queue is eligible for reassembly i.e. it is not COMPLETE, * the last and the first frames arrived and all the bits are here. */ -static u8 *ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, +static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, struct net_device *dev) { struct sk_buff *fp, *head = fq->fragments; - struct sk_buff *skb; + int remove_fraghdr = 0; int payload_len; - int unfrag_len; - int copy; - u8 *nhptr; - - /* - * we know the m_flag arrived and we have a queue, - * starting from 0, without gaps. - * this means we have all fragments. - */ + int nhoff; fq_kill(fq); @@ -527,40 +530,86 @@ BUG_TRAP(FRAG6_CB(head)->offset == 0); /* Unfragmented part is taken from the first segment. */ - unfrag_len = head->h.raw - (u8 *) (head->nh.ipv6h + 1); - payload_len = unfrag_len + fq->len; + payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len; + nhoff = head->h.raw - head->nh.raw; - if (payload_len > 65535) - goto out_oversize; + if (payload_len > 65535) { + payload_len -= 8; + if (payload_len > 65535) + goto out_oversize; + remove_fraghdr = 1; + } - if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) + /* Head of list must not be cloned. */ + if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) goto out_oom; - copy = unfrag_len + sizeof(struct ipv6hdr); - - skb->mac.raw = skb->data; - skb->nh.ipv6h = (struct ipv6hdr *) skb->data; - skb->dev = dev; - skb->protocol = __constant_htons(ETH_P_IPV6); - skb->pkt_type = head->pkt_type; - FRAG6_CB(skb)->h = FRAG6_CB(head)->h; - skb->dst = dst_clone(head->dst); - - memcpy(skb_put(skb, copy), head->nh.ipv6h, copy); - nhptr = skb->nh.raw + fq->nhoffset; - *nhptr = fq->nexthdr; - - skb->h.raw = skb->tail; - - skb->nh.ipv6h->payload_len = ntohs(payload_len); - - *skb_in = skb; + /* If the first fragment is fragmented itself, we split + * it to two chunks: the first with data and paged part + * and the second, holding only fragments. */ + if (skb_shinfo(head)->frag_list) { + struct sk_buff *clone; + int i, plen = 0; + + if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) + goto out_oom; + clone->next = head->next; + head->next = clone; + skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; + skb_shinfo(head)->frag_list = NULL; + for (i=0; i<skb_shinfo(head)->nr_frags; i++) + plen += skb_shinfo(head)->frags[i].size; + clone->len = clone->data_len = head->data_len - plen; + head->data_len -= clone->len; + head->len -= clone->len; + clone->csum = 0; + clone->ip_summed = head->ip_summed; + atomic_add(clone->truesize, &ip6_frag_mem); + } + + /* Normally we do not remove frag header from datagram, but + * we have to do this and to relocate header, when payload + * is > 65535-8. */ + if (remove_fraghdr) { + nhoff = fq->nhoffset; + head->nh.raw[nhoff] = head->h.raw[0]; + memmove(head->head+8, head->head, (head->data-head->head)-8); + head->mac.raw += 8; + head->nh.raw += 8; + } else { + ((struct frag_hdr*)head->h.raw)->frag_off = 0; + } - for (fp = fq->fragments; fp; fp=fp->next) - memcpy(skb_put(skb, fp->len), fp->data, fp->len); + skb_shinfo(head)->frag_list = head->next; + head->h.raw = head->data; + skb_push(head, head->data - head->nh.raw); + atomic_sub(head->truesize, &ip6_frag_mem); + + for (fp=head->next; fp; fp = fp->next) { + head->data_len += fp->len; + head->len += fp->len; + if (head->ip_summed != fp->ip_summed) + head->ip_summed = CHECKSUM_NONE; + else if (head->ip_summed == CHECKSUM_HW) + head->csum = csum_add(head->csum, fp->csum); + head->truesize += fp->truesize; + atomic_sub(fp->truesize, &ip6_frag_mem); + } + + head->next = NULL; + head->dev = dev; + head->stamp = fq->stamp; + head->nh.ipv6h->payload_len = ntohs(payload_len); + + *skb_in = head; + + /* Yes, and fold redundant checksum back. 8) */ + if (head->ip_summed == CHECKSUM_HW) + head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); IP6_INC_STATS_BH(Ip6ReasmOKs); - return nhptr; + fq->fragments = NULL; + return nhoff; out_oversize: if (net_ratelimit()) @@ -571,14 +620,14 @@ printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); out_fail: IP6_INC_STATS_BH(Ip6ReasmFails); - return NULL; + return -1; } -u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr) +int ipv6_reassembly(struct sk_buff **skbp, int nhoff) { struct sk_buff *skb = *skbp; - struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw); struct net_device *dev = skb->dev; + struct frag_hdr *fhdr; struct frag_queue *fq; struct ipv6hdr *hdr; @@ -588,31 +637,34 @@ /* Jumbo payload inhibits frag. header */ if (hdr->payload_len==0) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw); - return NULL; + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); + return -1; } - if ((u8 *)(fhdr+1) > skb->tail) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw); - return NULL; + if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); + return -1; } + hdr = skb->nh.ipv6h; + fhdr = (struct frag_hdr *)skb->h.raw; + if (!(fhdr->frag_off & __constant_htons(0xFFF9))) { /* It is not a fragmented frame */ skb->h.raw += sizeof(struct frag_hdr); IP6_INC_STATS_BH(Ip6ReasmOKs); - return &fhdr->nexthdr; + return (u8*)fhdr - skb->nh.raw; } if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) ip6_evictor(); if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) { - u8 *ret = NULL; + int ret = -1; spin_lock(&fq->lock); - ip6_frag_queue(fq, skb, fhdr, nhptr); + ip6_frag_queue(fq, skb, fhdr, nhoff); if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) @@ -625,5 +677,5 @@ IP6_INC_STATS_BH(Ip6ReasmFails); kfree_skb(skb); - return NULL; + return -1; } diff -u --recursive --new-file v2.4.3/linux/net/ipv6/sit.c linux/net/ipv6/sit.c --- v2.4.3/linux/net/ipv6/sit.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv6/sit.c Thu Apr 12 12:11:39 2001 @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: sit.c,v 1.47 2000/11/28 13:49:22 davem Exp $ + * $Id: sit.c,v 1.49 2001/03/19 20:31:17 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -229,7 +229,7 @@ } -void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len) +void ipip6_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -237,14 +237,11 @@ 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)dp; + struct iphdr *iph = (struct iphdr*)skb->data; int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; - if (len < sizeof(struct iphdr)) - return; - switch (type) { default: case ICMP_PARAMETERPROB: @@ -382,20 +379,22 @@ IP6_ECN_set_ce(skb->nh.ipv6h); } -int ipip6_rcv(struct sk_buff *skb, unsigned short len) +int ipip6_rcv(struct sk_buff *skb) { struct iphdr *iph; struct ip_tunnel *tunnel; + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto out; + iph = skb->nh.iph; read_lock(&ipip6_lock); if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data); + skb->nh.raw = skb->data; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = __constant_htons(ETH_P_IPV6); - skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; @@ -418,6 +417,7 @@ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); kfree_skb(skb); read_unlock(&ipip6_lock); +out: return 0; } @@ -842,7 +842,7 @@ void sit_cleanup(void) { inet_del_protocol(&sit_protocol); - unregister_netdevice(&ipip6_fb_tunnel_dev); + unregister_netdev(&ipip6_fb_tunnel_dev); } #endif @@ -852,13 +852,7 @@ ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel; strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name); -#ifdef MODULE register_netdev(&ipip6_fb_tunnel_dev); -#else - rtnl_lock(); - register_netdevice(&ipip6_fb_tunnel_dev); - rtnl_unlock(); -#endif inet_add_protocol(&sit_protocol); return 0; } diff -u --recursive --new-file v2.4.3/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.4.3/linux/net/ipv6/tcp_ipv6.c Sun Mar 25 18:14:25 2001 +++ linux/net/ipv6/tcp_ipv6.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.128 2000/12/08 17:15:54 davem Exp $ + * $Id: tcp_ipv6.c,v 1.135 2001/04/06 18:41:36 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -635,6 +635,7 @@ } ip6_dst_store(sk, dst, NULL); + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; if (saddr == NULL) { err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf); @@ -678,25 +679,23 @@ failure: __sk_dst_reset(sk); sk->dport = 0; + sk->route_caps = 0; return err; } -void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, - struct inet6_skb_parm *opt, - int type, int code, unsigned char *header, __u32 info) +void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) { + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; struct in6_addr *saddr = &hdr->saddr; struct in6_addr *daddr = &hdr->daddr; - struct tcphdr *th = (struct tcphdr *)header; + struct tcphdr *th = (struct tcphdr *)(skb->data+offset); struct ipv6_pinfo *np; struct sock *sk; int err; struct tcp_opt *tp; __u32 seq; - if (header + 8 > skb->tail) - return; - sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex); if (sk == NULL) { @@ -914,10 +913,15 @@ struct sk_buff *skb) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; - - th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, - csum_partial((char *)th, th->doff<<2, - skb->csum)); + + if (skb->ip_summed == CHECKSUM_HW) { + th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); + skb->csum = offsetof(struct tcphdr, check); + } else { + th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, + csum_partial((char *)th, th->doff<<2, + skb->csum)); + } } @@ -1298,6 +1302,7 @@ MOD_INC_USE_COUNT; ip6_dst_store(newsk, dst, NULL); + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; newtp = &(newsk->tp_pinfo.af_tcp); @@ -1371,22 +1376,20 @@ static int tcp_v6_checksum_init(struct sk_buff *skb) { if (skb->ip_summed == CHECKSUM_HW) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr,skb->csum)) + return 0; + NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n")); + } + if (skb->len <= 76) { if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr,skb->csum)) { - NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n")); + &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0))) return -1; - } skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - if (skb->len <= 76) { - if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr,csum_partial((char *)skb->h.th, skb->len, 0))) - return -1; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, - &skb->nh.ipv6h->daddr,0); - } + skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr,0); } return 0; } @@ -1526,46 +1529,45 @@ return 0; } -int tcp_v6_rcv(struct sk_buff *skb, unsigned long len) +int tcp_v6_rcv(struct sk_buff *skb) { struct tcphdr *th; struct sock *sk; - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; int ret; - th = skb->h.th; - if (skb->pkt_type != PACKET_HOST) goto discard_it; /* - * Pull up the IP header. + * Count it even if it's bad. */ + TCP_INC_STATS_BH(TcpInSegs); - __skb_pull(skb, skb->h.raw - skb->data); + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) + goto discard_it; - /* - * Count it even if it's bad. - */ + th = skb->h.th; - TCP_INC_STATS_BH(TcpInSegs); + if (th->doff < sizeof(struct tcphdr)/4) + goto bad_packet; + if (!pskb_may_pull(skb, th->doff*4)) + goto discard_it; - if (th->doff < sizeof(struct tcphdr)/4 || - (skb->ip_summed != CHECKSUM_UNNECESSARY && + if ((skb->ip_summed != CHECKSUM_UNNECESSARY && tcp_v6_checksum_init(skb) < 0)) goto bad_packet; + th = skb->h.th; TCP_SKB_CB(skb)->seq = ntohl(th->seq); TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - len - th->doff*4); + skb->len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->when = 0; TCP_SKB_CB(skb)->flags = ip6_get_dsfield(skb->nh.ipv6h); TCP_SKB_CB(skb)->sacked = 0; - skb->used = 0; - sk = __tcp_v6_lookup(saddr, th->source, daddr, ntohs(th->dest), tcp_v6_iif(skb)); + sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source, + &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); if (!sk) goto no_tcp_socket; @@ -1591,7 +1593,7 @@ return ret; no_tcp_socket: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); } else { @@ -1612,7 +1614,7 @@ goto discard_it; do_time_wait: - if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); sock_put(sk); goto discard_it; @@ -1673,10 +1675,12 @@ if (dst->error) { err = dst->error; dst_release(dst); + sk->route_caps = 0; return err; } ip6_dst_store(sk, dst, NULL); + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM; } return 0; @@ -1837,7 +1841,7 @@ /* Cleanup up the write buffer. */ tcp_writequeue_purge(sk); - /* Cleans up our, hopefuly empty, out_of_order_queue. */ + /* Cleans up our, hopefully empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); /* Clean prequeue, it must be empty really */ @@ -1847,6 +1851,10 @@ if(sk->prev != NULL) tcp_put_port(sk); + /* If sendmsg cached page exists, toss it. */ + if (tp->sndmsg_page != NULL) + __free_page(tp->sndmsg_page); + atomic_dec(&tcp_sockets_allocated); return inet6_destroy_sock(sk); @@ -1967,7 +1975,7 @@ off_t begin, pos = 0; char tmpbuf[LINE_LEN+2]; - if(offset < LINE_LEN+1) + if (offset < LINE_LEN+1) len += sprintf(buffer, LINE_FMT, " sl " /* 6 */ "local_address " /* 38 */ @@ -1997,7 +2005,7 @@ if (pos >= offset) { get_tcp6_sock(sk, tmpbuf, num); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if (len >= length) { + if (pos >= offset + length) { tcp_listen_unlock(); goto out_no_bh; } @@ -2016,7 +2024,7 @@ continue; get_openreq6(sk, req, tmpbuf, num, uid); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock_bh(&tp->syn_wait_lock); tcp_listen_unlock(); goto out_no_bh; @@ -2048,7 +2056,7 @@ continue; get_tcp6_sock(sk, tmpbuf, num); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2063,7 +2071,7 @@ continue; get_timewait6_sock(tw, tmpbuf, num); len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) { + if (pos >= offset + length) { read_unlock(&head->lock); goto out; } @@ -2078,7 +2086,7 @@ begin = len - (pos - offset); *start = buffer + begin; len -= begin; - if(len > length) + if (len > length) len = length; if (len < 0) len = 0; diff -u --recursive --new-file v2.4.3/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.4.3/linux/net/ipv6/udp.c Mon Jan 1 11:01:58 2001 +++ linux/net/ipv6/udp.c Thu Apr 12 12:11:39 2001 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.59 2000/11/28 13:38:38 davem Exp $ + * $Id: udp.c,v 1.62 2001/03/06 21:15:11 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -391,13 +391,13 @@ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else if (msg->msg_flags&MSG_TRUNC) { - if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) + if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) goto csum_copy_err; err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else { - err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr)); - if (err) + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + if (err == -EINVAL) goto csum_copy_err; } if (err) @@ -461,22 +461,17 @@ goto out_free; } -void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr, - struct inet6_skb_parm *opt, - int type, int code, unsigned char *buff, __u32 info) +void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) { + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; struct net_device *dev = skb->dev; struct in6_addr *saddr = &hdr->saddr; struct in6_addr *daddr = &hdr->daddr; + struct udphdr *uh = (struct udphdr*)(skb->data+offset); struct sock *sk; - struct udphdr *uh; int err; - if (buff + sizeof(struct udphdr) > skb->tail) - return; - - uh = (struct udphdr *) buff; - sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex); if (sk == NULL) @@ -577,8 +572,8 @@ buff = NULL; sk2 = sk; - while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr, - uh->source, daddr, dif))) { + while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr, + uh->source, saddr, dif))) { if (!buff) { buff = skb_clone(skb, GFP_ATOMIC); if (!buff) @@ -596,31 +591,29 @@ read_unlock(&udp_hash_lock); } -int udpv6_rcv(struct sk_buff *skb, unsigned long len) +int udpv6_rcv(struct sk_buff *skb) { struct sock *sk; struct udphdr *uh; struct net_device *dev = skb->dev; - struct in6_addr *saddr = &skb->nh.ipv6h->saddr; - struct in6_addr *daddr = &skb->nh.ipv6h->daddr; - u32 ulen; + struct in6_addr *saddr, *daddr; + u32 ulen = 0; + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto short_packet; + + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; uh = skb->h.uh; - __skb_pull(skb, skb->h.raw - skb->data); ulen = ntohs(uh->len); /* Check for jumbo payload */ - if (ulen == 0 && skb->nh.ipv6h->payload_len == 0) - ulen = len; + if (ulen == 0) + ulen = skb->len; - if (ulen > len || len < sizeof(*uh)) { - if (net_ratelimit()) - printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len); - UDP6_INC_STATS_BH(UdpInErrors); - kfree_skb(skb); - return(0); - } + if (ulen > skb->len || ulen < sizeof(*uh)) + goto short_packet; if (uh->check == 0) { /* IPv6 draft-v2 section 8.1 says that we SHOULD log @@ -631,17 +624,24 @@ goto discard; } - skb_trim(skb, ulen); + if (ulen < skb->len) { + if (__pskb_trim(skb, ulen)) + goto discard; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + uh = skb->h.uh; + } if (skb->ip_summed==CHECKSUM_HW) { - if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) - goto discard; skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) + if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) { + NETDEBUG(printk(KERN_DEBUG "udp v6 hw csum failure.\n")); + skb->ip_summed = CHECKSUM_NONE; + } + } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); - len = ulen; - /* * Multicast receive code */ @@ -656,12 +656,11 @@ * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex); - + if (sk == NULL) { if (skb->ip_summed != CHECKSUM_UNNECESSARY && - (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum))) + (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) goto discard; UDP6_INC_STATS_BH(UdpNoPorts); @@ -676,7 +675,11 @@ udpv6_queue_rcv_skb(sk, skb); sock_put(sk); return(0); - + +short_packet: + if (net_ratelimit()) + printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len); + discard: UDP6_INC_STATS_BH(UdpInErrors); kfree_skb(skb); diff -u --recursive --new-file v2.4.3/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.4.3/linux/net/ipx/af_ipx.c Mon Mar 26 15:43:01 2001 +++ linux/net/ipx/af_ipx.c Thu Apr 12 12:11:39 2001 @@ -123,7 +123,7 @@ static unsigned char ipxcfg_max_hops = 16; static char ipxcfg_auto_select_primary; static char ipxcfg_auto_create_interfaces; -static int sysctl_ipx_pprop_broadcasting = 1; +int sysctl_ipx_pprop_broadcasting = 1; /* Global Variables */ static struct datalink_proto *p8022_datalink; @@ -1542,7 +1542,7 @@ ipx_offset = intrfc->if_ipx_offset; size = sizeof(struct ipxhdr) + len + ipx_offset; - skb = sock_alloc_send_skb(sk, size, 0, noblock, &err); + skb = sock_alloc_send_skb(sk, size, noblock, &err); if (!skb) goto out_put; @@ -2531,6 +2531,7 @@ sendmsg: ipx_sendmsg, recvmsg: ipx_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --recursive --new-file v2.4.3/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c --- v2.4.3/linux/net/ipx/af_spx.c Sun Aug 6 22:20:09 2000 +++ linux/net/ipx/af_spx.c Thu Apr 12 12:11:39 2001 @@ -440,7 +440,7 @@ save_flags(flags); cli(); - skb = sock_alloc_send_skb(sk, size, 1, 0, &err); + skb = sock_alloc_send_skb(sk, size, 0, &err); if(skb == NULL) { restore_flags(flags); return (-ENOMEM); @@ -742,7 +742,7 @@ size = offset + sizeof(struct ipxspxhdr) + len; cli(); - skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err); sti(); if(skb == NULL) return (err); @@ -901,6 +901,7 @@ sendmsg: spx_sendmsg, recvmsg: spx_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --recursive --new-file v2.4.3/linux/net/ipx/sysctl_net_ipx.c linux/net/ipx/sysctl_net_ipx.c --- v2.4.3/linux/net/ipx/sysctl_net_ipx.c Sun Mar 25 18:14:25 2001 +++ linux/net/ipx/sysctl_net_ipx.c Thu Apr 12 12:16:36 2001 @@ -6,6 +6,7 @@ * Added /proc/sys/net/ipx/ipx_pprop_broadcasting - acme March 4, 2001 */ +#include <linux/config.h> #include <linux/mm.h> #include <linux/sysctl.h> diff -u --recursive --new-file v2.4.3/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.4.3/linux/net/irda/af_irda.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/af_irda.c Thu Apr 12 12:11:39 2001 @@ -1257,7 +1257,7 @@ len = self->max_data_size; } - skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, + skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; @@ -1500,7 +1500,7 @@ len = self->max_data_size; } - skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, + skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; @@ -1563,7 +1563,7 @@ len = self->max_data_size; } - skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, + skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; @@ -2256,6 +2256,7 @@ sendmsg: irda_sendmsg, recvmsg: irda_recvmsg_stream, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = { @@ -2276,6 +2277,7 @@ sendmsg: irda_sendmsg, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { @@ -2296,6 +2298,7 @@ sendmsg: irda_sendmsg_dgram, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #ifdef CONFIG_IRDA_ULTRA @@ -2317,6 +2320,7 @@ sendmsg: irda_sendmsg_ultra, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #endif /* CONFIG_IRDA_ULTRA */ diff -u --recursive --new-file v2.4.3/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c --- v2.4.3/linux/net/lapb/lapb_iface.c Fri Feb 16 16:06:17 2001 +++ linux/net/lapb/lapb_iface.c Thu Apr 12 12:16:36 2001 @@ -15,7 +15,6 @@ * 2000-10-29 Henner Eisen lapb_data_indication() return status. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/types.h> diff -u --recursive --new-file v2.4.3/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c --- v2.4.3/linux/net/netlink/af_netlink.c Fri Feb 9 11:29:44 2001 +++ linux/net/netlink/af_netlink.c Thu Apr 12 12:11:39 2001 @@ -962,6 +962,7 @@ sendmsg: netlink_sendmsg, recvmsg: netlink_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family netlink_family_ops = { diff -u --recursive --new-file v2.4.3/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.4.3/linux/net/netrom/af_netrom.c Fri Dec 29 14:35:47 2000 +++ linux/net/netrom/af_netrom.c Thu Apr 12 12:11:39 2001 @@ -407,6 +407,9 @@ if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch (optname) { case NETROM_T1: val = sk->protinfo.nr->t1 / HZ; @@ -1010,7 +1013,7 @@ SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, size - len); @@ -1224,10 +1227,9 @@ return(len); } -static struct net_proto_family nr_family_ops = -{ - PF_NETROM, - nr_create +static struct net_proto_family nr_family_ops = { + family: PF_NETROM, + create: nr_create, }; static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = { @@ -1248,22 +1250,29 @@ sendmsg: nr_sendmsg, recvmsg: nr_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> SOCKOPS_WRAP(nr_proto, PF_NETROM); static struct notifier_block nr_dev_notifier = { - nr_device_event, - 0 + notifier_call: nr_device_event, }; static struct net_device *dev_nr; +static const char banner[] __initdata = KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n"; + static int __init nr_proto_init(void) { int i; + if (nr_ndevs * sizeof(struct net_device) >= KMALLOC_MAXSIZE) { + printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n"); + return -1; + } + if ((dev_nr = kmalloc(nr_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); return -1; @@ -1279,7 +1288,7 @@ sock_register(&nr_family_ops); register_netdevice_notifier(&nr_dev_notifier); - printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n"); + printk(banner); ax25_protocol_register(AX25_P_NETROM, nr_route_frame); ax25_linkfail_register(nr_link_failed); diff -u --recursive --new-file v2.4.3/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c --- v2.4.3/linux/net/netrom/nr_out.c Fri Dec 29 14:44:46 2000 +++ linux/net/netrom/nr_out.c Thu Apr 12 12:11:39 2001 @@ -56,7 +56,7 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL) return; skb_reserve(skbn, frontlen); diff -u --recursive --new-file v2.4.3/linux/net/netsyms.c linux/net/netsyms.c --- v2.4.3/linux/net/netsyms.c Sun Mar 25 18:24:31 2001 +++ linux/net/netsyms.c Thu Apr 12 12:11:39 2001 @@ -130,15 +130,27 @@ EXPORT_SYMBOL(sock_no_sendmsg); EXPORT_SYMBOL(sock_no_recvmsg); EXPORT_SYMBOL(sock_no_mmap); +EXPORT_SYMBOL(sock_no_sendpage); EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); EXPORT_SYMBOL(sock_rmalloc); +EXPORT_SYMBOL(skb_linearize); +EXPORT_SYMBOL(skb_checksum); +EXPORT_SYMBOL(skb_checksum_help); EXPORT_SYMBOL(skb_recv_datagram); EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_copy_datagram); EXPORT_SYMBOL(skb_copy_datagram_iovec); +EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); +EXPORT_SYMBOL(skb_copy_bits); +EXPORT_SYMBOL(skb_copy_and_csum_bits); EXPORT_SYMBOL(skb_copy_expand); +EXPORT_SYMBOL(___pskb_trim); +EXPORT_SYMBOL(__pskb_pull_tail); +EXPORT_SYMBOL(pskb_expand_head); +EXPORT_SYMBOL(pskb_copy); +EXPORT_SYMBOL(skb_realloc_headroom); EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(put_cmsg); EXPORT_SYMBOL(sock_kmalloc); @@ -225,7 +237,6 @@ EXPORT_SYMBOL(ip_route_output_key); EXPORT_SYMBOL(ip_route_input); EXPORT_SYMBOL(icmp_send); -EXPORT_SYMBOL(icmp_reply); EXPORT_SYMBOL(ip_options_compile); EXPORT_SYMBOL(ip_options_undo); EXPORT_SYMBOL(arp_send); @@ -295,7 +306,6 @@ EXPORT_SYMBOL(ip_queue_xmit); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(csum_partial_copy_fromiovecend); -EXPORT_SYMBOL(copy_and_csum_toiovec); EXPORT_SYMBOL(tcp_v4_lookup_listener); /* UDP/TCP exported functions for TCPv6 */ EXPORT_SYMBOL(udp_ioctl); @@ -362,6 +372,7 @@ EXPORT_SYMBOL(sysctl_tcp_wmem); EXPORT_SYMBOL(sysctl_tcp_ecn); EXPORT_SYMBOL(tcp_cwnd_application_limited); +EXPORT_SYMBOL(tcp_sendpage); EXPORT_SYMBOL(xrlim_allow); diff -u --recursive --new-file v2.4.3/linux/net/packet/af_packet.c linux/net/packet/af_packet.c --- v2.4.3/linux/net/packet/af_packet.c Fri Feb 9 11:29:44 2001 +++ linux/net/packet/af_packet.c Thu Apr 12 12:11:39 2001 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.47 2000/12/08 17:15:54 davem Exp $ + * Version: $Id: af_packet.c,v 1.54 2001/03/03 01:20:11 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -149,7 +149,7 @@ */ /* List of all packet sockets. */ -static struct sock * packet_sklist = NULL; +static struct sock * packet_sklist; static rwlock_t packet_sklist_lock = RW_LOCK_UNLOCKED; atomic_t packet_socks_nr; @@ -404,6 +404,7 @@ struct sockaddr_ll *sll; struct packet_opt *po; u8 * skb_head = skb->data; + int skb_len = skb->len; #ifdef CONFIG_FILTER unsigned snaplen; #endif @@ -461,7 +462,7 @@ if (skb_head != skb->data) { skb->data = skb_head; - skb->len = skb->tail - skb->data; + skb->len = skb_len; } kfree_skb(skb); skb = nskb; @@ -479,8 +480,8 @@ sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); #ifdef CONFIG_FILTER - if (skb->len > snaplen) - __skb_trim(skb, snaplen); + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; #endif skb_set_owner_r(skb, sk); @@ -502,7 +503,7 @@ #endif if (skb_head != skb->data && skb_shared(skb)) { skb->data = skb_head; - skb->len = skb->tail - skb->data; + skb->len = skb_len; } drop: kfree_skb(skb); @@ -517,6 +518,7 @@ struct sockaddr_ll *sll; struct tpacket_hdr *h; u8 * skb_head = skb->data; + int skb_len = skb->len; unsigned snaplen; unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; unsigned short macoff, netoff; @@ -534,6 +536,8 @@ else if (skb->pkt_type == PACKET_OUTGOING) { /* Special case: outgoing packets have ll header at head */ skb_pull(skb, skb->nh.raw - skb->data); + if (skb->ip_summed == CHECKSUM_HW) + status |= TP_STATUS_CSUMNOTREADY; } } @@ -580,6 +584,8 @@ if ((int)snaplen < 0) snaplen = 0; } + if (snaplen > skb->len-skb->data_len) + snaplen = skb->len-skb->data_len; spin_lock(&sk->receive_queue.lock); h = po->iovec[po->head]; @@ -623,7 +629,7 @@ drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { skb->data = skb_head; - skb->len = skb->tail - skb->data; + skb->len = skb_len; } drop: kfree_skb(skb); @@ -682,7 +688,7 @@ if (len > dev->mtu+reserve) goto out_unlock; - skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL) goto out_unlock; @@ -1051,8 +1057,7 @@ msg->msg_flags|=MSG_TRUNC; } - /* We can't use skb_copy_datagram here */ - err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto out_free; @@ -1318,6 +1323,9 @@ if (get_user(len,optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch(optname) { case PACKET_STATISTICS: { @@ -1780,6 +1788,7 @@ sendmsg: packet_sendmsg_spkt, recvmsg: packet_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #endif @@ -1801,17 +1810,16 @@ sendmsg: packet_sendmsg, recvmsg: packet_recvmsg, mmap: packet_mmap, + sendpage: sock_no_sendpage, }; static struct net_proto_family packet_family_ops = { - PF_PACKET, - packet_create + family: PF_PACKET, + create: packet_create, }; -struct notifier_block packet_netdev_notifier={ - packet_notifier, - NULL, - 0 +static struct notifier_block packet_netdev_notifier = { + notifier_call: packet_notifier, }; #ifdef CONFIG_PROC_FS @@ -1864,19 +1872,14 @@ } #endif - - static void __exit packet_exit(void) { -#ifdef CONFIG_PROC_FS remove_proc_entry("net/packet", 0); -#endif unregister_netdevice_notifier(&packet_netdev_notifier); sock_unregister(PF_PACKET); return; } - static int __init packet_init(void) { sock_register(&packet_family_ops); @@ -1886,7 +1889,6 @@ #endif return 0; } - module_init(packet_init); module_exit(packet_exit); diff -u --recursive --new-file v2.4.3/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.4.3/linux/net/rose/af_rose.c Fri Dec 29 14:35:47 2000 +++ linux/net/rose/af_rose.c Thu Apr 12 12:11:39 2001 @@ -70,7 +70,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC; int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; -static struct sock *volatile rose_list = NULL; +static struct sock *rose_list; static struct proto_ops rose_proto_ops; @@ -471,7 +471,10 @@ if (get_user(len, optlen)) return -EFAULT; - + + if (len < 0) + return -EINVAL; + switch (optname) { case ROSE_DEFER: val = sk->protinfo.rose->defer; @@ -1056,7 +1059,7 @@ SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN); @@ -1118,7 +1121,7 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL) + if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL) return err; skbn->sk = sk; @@ -1414,6 +1417,7 @@ sendmsg: rose_sendmsg, recvmsg: rose_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --recursive --new-file v2.4.3/linux/net/socket.c linux/net/socket.c --- v2.4.3/linux/net/socket.c Fri Nov 17 11:36:27 2000 +++ linux/net/socket.c Thu Apr 12 12:11:39 2001 @@ -71,6 +71,7 @@ #include <linux/poll.h> #include <linux/cache.h> #include <linux/module.h> +#include <linux/highmem.h> #if defined(CONFIG_KMOD) && defined(CONFIG_NET) #include <linux/kmod.h> @@ -104,6 +105,8 @@ unsigned long count, loff_t *ppos); static ssize_t sock_writev(struct file *file, const struct iovec *vector, unsigned long count, loff_t *ppos); +static ssize_t sock_writepage(struct file *file, struct page *page, + int offset, size_t size, loff_t *ppos, int more); /* @@ -122,7 +125,8 @@ release: sock_close, fasync: sock_fasync, readv: sock_readv, - writev: sock_writev + writev: sock_writev, + writepage: sock_writepage }; /* @@ -602,6 +606,24 @@ return sock_sendmsg(sock, &msg, size); } +ssize_t sock_writepage(struct file *file, struct page *page, + int offset, size_t size, loff_t *ppos, int more) +{ + struct socket *sock; + int flags; + + if (ppos != &file->f_pos) + return -ESPIPE; + + sock = socki_lookup(file->f_dentry->d_inode); + + flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; + if (more) + flags |= MSG_MORE; + + return sock->ops->sendpage(sock, page, offset, size, flags); +} + int sock_readv_writev(int type, struct inode * inode, struct file * file, const struct iovec * iov, long count, long size) { @@ -1269,7 +1291,10 @@ { int err; struct socket *sock; - + + if (optlen < 0) + return -EINVAL; + if ((sock = sockfd_lookup(fd, &err))!=NULL) { if (level == SOL_SOCKET) diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.4.3/linux/net/sunrpc/sched.c Fri Feb 9 11:29:44 2001 +++ linux/net/sunrpc/sched.c Tue Apr 3 13:45:37 2001 @@ -1072,6 +1072,8 @@ current->pgrp = 1; strcpy(current->comm, "rpciod"); + current->flags |= PF_MEMALLOC; + dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid); while (rpciod_users) { if (signalled()) { diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.4.3/linux/net/sunrpc/svcsock.c Wed Mar 14 14:37:36 2001 +++ linux/net/sunrpc/svcsock.c Thu Apr 12 12:11:39 2001 @@ -381,10 +381,17 @@ dprintk("svc: recvfrom returned error %d\n", -err); } + /* Sorry. */ + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + svc_sock_received(svsk, 0); + return 0; + } + } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) { - unsigned int csum = skb->csum; - csum = csum_partial(skb->h.raw, skb->len, csum); - if ((unsigned short)csum_fold(csum)) { + if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { skb_free_datagram(svsk->sk_sk, skb); svc_sock_received(svsk, 0); return 0; @@ -395,7 +402,7 @@ svsk->sk_data = 1; len = skb->len - sizeof(struct udphdr); - data = (u32 *) (skb->h.raw + sizeof(struct udphdr)); + data = (u32 *) (skb->data + sizeof(struct udphdr)); rqstp->rq_skbuff = skb; rqstp->rq_argbuf.base = data; diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/sysctl.c linux/net/sunrpc/sysctl.c --- v2.4.3/linux/net/sunrpc/sysctl.c Sun Oct 1 20:35:16 2000 +++ linux/net/sunrpc/sysctl.c Fri Apr 13 20:26:07 2001 @@ -63,7 +63,7 @@ { char tmpbuf[20], *p, c; unsigned int value; - int left, len; + size_t left, len; if ((file->f_pos && !write) || !*lenp) { *lenp = 0; diff -u --recursive --new-file v2.4.3/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c --- v2.4.3/linux/net/sunrpc/xprt.c Fri Feb 9 11:29:44 2001 +++ linux/net/sunrpc/xprt.c Thu Apr 12 12:11:39 2001 @@ -591,7 +591,7 @@ struct sk_buff *skb, int copied) { - __u8 *pkt_data = skb->h.raw + sizeof(struct udphdr); + int offset = sizeof(struct udphdr); __u8 *cur_ptr = iov->iov_base; __kernel_size_t cur_len = iov->iov_len; unsigned int csum = skb->csum; @@ -599,18 +599,18 @@ int slack = skb->len - copied - sizeof(struct udphdr); if (need_csum) - csum = csum_partial(skb->h.raw, sizeof(struct udphdr), csum); + csum = csum_partial(skb->data, sizeof(struct udphdr), csum); while (copied > 0) { if (cur_len) { int to_move = cur_len; if (to_move > copied) to_move = copied; if (need_csum) - csum = csum_partial_copy_nocheck(pkt_data, cur_ptr, - to_move, csum); + csum = skb_copy_and_csum_bits(skb, offset, cur_ptr, + to_move, csum); else - memcpy(cur_ptr, pkt_data, to_move); - pkt_data += to_move; + skb_copy_bits(skb, offset, cur_ptr, to_move); + offset += to_move; copied -= to_move; cur_ptr += to_move; cur_len -= to_move; @@ -623,7 +623,7 @@ } if (need_csum) { if (slack > 0) - csum = csum_partial(pkt_data, slack, csum); + csum = skb_checksum(skb, offset, slack, csum); if ((unsigned short)csum_fold(csum)) return -1; } @@ -1116,6 +1116,7 @@ struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; struct rpc_rqst *req = task->tk_rqstp; + spin_lock_bh(&xprt_sock_lock); spin_lock(&xprt_lock); if (xprt->snd_task && xprt->snd_task != task) { dprintk("RPC: %4d TCP write queue full (task %d)\n", @@ -1131,6 +1132,7 @@ req->rq_bytes_sent = 0; } spin_unlock(&xprt_lock); + spin_unlock_bh(&xprt_sock_lock); return xprt->snd_task == task; } @@ -1143,10 +1145,12 @@ struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; if (xprt->snd_task && xprt->snd_task == task) { + spin_lock_bh(&xprt_sock_lock); spin_lock(&xprt_lock); xprt->snd_task = NULL; rpc_wake_up_next(&xprt->sending); spin_unlock(&xprt_lock); + spin_unlock_bh(&xprt_sock_lock); } } diff -u --recursive --new-file v2.4.3/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.4.3/linux/net/unix/af_unix.c Tue Mar 6 19:44:37 2001 +++ linux/net/unix/af_unix.c Thu Apr 12 12:11:39 2001 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.111 2001/02/02 11:37:28 davem Exp $ + * Version: $Id: af_unix.c,v 1.116 2001/03/03 01:20:11 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. @@ -1182,7 +1182,7 @@ if ((unsigned)len > sk->sndbuf - 32) goto out; - skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err); if (skb==NULL) goto out; @@ -1285,7 +1285,6 @@ struct sockaddr_un *sunaddr=msg->msg_name; int err,size; struct sk_buff *skb; - int limit=0; int sent=0; err = -EOPNOTSUPP; @@ -1323,21 +1322,10 @@ size = (128 * 1024) / 2; /* - * Keep to page sized kmalloc()'s as various people - * have suggested. Big mallocs stress the vm too - * much. - */ - - if (size > PAGE_SIZE-16) - limit = PAGE_SIZE-16; /* Fall back to a page if we can't grab a big buffer this instant */ - else - limit = 0; /* Otherwise just grab and wait */ - - /* * Grab a buffer */ - skb=sock_alloc_send_skb(sk,size,limit,msg->msg_flags&MSG_DONTWAIT, &err); + skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err); if (skb==NULL) goto out_err; @@ -1821,6 +1809,7 @@ sendmsg: unix_stream_sendmsg, recvmsg: unix_stream_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct proto_ops unix_dgram_ops = { @@ -1841,6 +1830,7 @@ sendmsg: unix_dgram_sendmsg, recvmsg: unix_dgram_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; struct net_proto_family unix_family_ops = { diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/Makefile linux/net/wanrouter/Makefile --- v2.4.3/linux/net/wanrouter/Makefile Fri Dec 29 14:07:24 2000 +++ linux/net/wanrouter/Makefile Thu Apr 12 12:11:39 2001 @@ -12,7 +12,7 @@ export-objs := wanmain.o obj-y := wanproc.o wanmain.o -obj-m := $(O_TARGET) +obj-m := $(O_TARGET) af_wanpipe.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/af_wanpipe.c linux/net/wanrouter/af_wanpipe.c --- v2.4.3/linux/net/wanrouter/af_wanpipe.c Wed Dec 31 16:00:00 1969 +++ linux/net/wanrouter/af_wanpipe.c Thu Apr 12 12:11:39 2001 @@ -0,0 +1,2765 @@ +/***************************************************************************** +* af_wanpipe.c WANPIPE(tm) Secure Socket Layer. +* +* Author: Nenad Corbic <ncorbic@sangoma.com> +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* 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. +* ============================================================================ +* Due Credit: +* Wanpipe socket layer is based on Packet and +* the X25 socket layers. The above sockets were +* used for the specific use of Sangoma Technoloiges +* API programs. +* Packet socket Authors: Ross Biro, Fred N. van Kempen and +* Alan Cox. +* X25 socket Author: Jonathan Naylor. +* ============================================================================ +* Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. +* Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. +* Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. +* Server and client applicaton can run +* simultaneously without conflicts. +* Feb 29, 2000 Nenad Corbic o Added support for PVC protocols, such as +* CHDLC, Frame Relay and HDLC API. +* Jan 17, 2000 Nenad Corbic o Initial version, based on AF_PACKET socket. +* X25API support only. +* +******************************************************************************/ + +#include <linux/version.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/fcntl.h> +#include <linux/socket.h> +#include <linux/in.h> +#include <linux/inet.h> +#include <linux/netdevice.h> +#include <linux/poll.h> +#include <linux/wireless.h> +#include <linux/kmod.h> +#include <net/ip.h> +#include <net/protocol.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <linux/errno.h> +#include <linux/timer.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/wanpipe.h> +#include <linux/if_wanpipe.h> +#include <linux/pkt_sched.h> +#include <linux/tcp.h> +#include <linux/if_wanpipe_common.h> +#include <linux/sdla_x25.h> + +#ifdef CONFIG_INET +#include <net/inet_common.h> +#endif + +#define SLOW_BACKOFF 0.1*HZ +#define FAST_BACKOFF 0.01*HZ + +//#define PRINT_DEBUG +#ifdef PRINT_DEBUG + #define DBG_PRINTK(format, a...) printk(format, ## a) +#else + #define DBG_PRINTK(format, a...) +#endif + +#if defined(LINUX_2_1) + #define dev_put(a) + #define __sock_put(a) + #define sock_hold(a) + #define DECLARE_WAITQUEUE(a,b) \ + struct wait_queue a = { b, NULL } +#endif + +/* SECURE SOCKET IMPLEMENTATION + * + * TRANSMIT: + * + * When the user sends a packet via send() system call + * the wanpipe_sendmsg() function is executed. + * + * Each packet is enqueud into sk->write_queue transmit + * queue. When the packet is enqueued, a delayed transmit + * timer is triggerd which acts as a Bottom Half hander. + * + * wanpipe_delay_transmit() function (BH), dequeues packets + * from the sk->write_queue transmit queue and sends it + * to the deriver via dev->hard_start_xmit(skb, dev) function. + * Note, this function is actual a function pointer of if_send() + * routine in the wanpipe driver. + * + * X25API GUARANTEED DELIVERY: + * + * In order to provide 100% guaranteed packet delivery, + * an atomic 'packet_sent' counter is implemented. Counter + * is incremented for each packet enqueued + * into sk->write_queue. Counter is decremented each + * time wanpipe_delayed_transmit() function successfuly + * passes the packet to the driver. Before each send(), a poll + * routine checks the sock resources The maximum value of + * packet sent counter is 1, thus if one packet is queued, the + * application will block untill that packet is passed to the + * driver. + * + * RECEIVE: + * + * Wanpipe device drivers call the socket bottom half + * function, wanpipe_rcv() to queue the incoming packets + * into an AF_WANPIPE socket queue. Based on wanpipe_rcv() + * return code, the driver knows whether the packet was + * sucessfully queued. If the socket queue is full, + * protocol flow control is used by the driver, if any, + * to slow down the traffic untill the sock queue is free. + * + * Every time a packet arrives into a socket queue the + * socket wakes up processes which are waiting to receive + * data. + * + * If the socket queue is full, the driver sets a block + * bit which signals the socket to kick the wanpipe driver + * bottom half hander when the socket queue is partialy + * empty. wanpipe_recvmsg() function performs this action. + * + * In case of x25api, packets will never be dropped, since + * flow control is available. + * + * In case of streaming protocols like CHDLC, packets will + * be dropped but the statistics will be generated. + */ + + +/* The code below is used to test memory leaks. It prints out + * a message every time kmalloc and kfree system calls get executed. + * If the calls match there is no leak :) + */ + +/***********FOR DEBUGGING PURPOSES********************************************* +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + void * v = kmalloc(size,prio); + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +******************************************************************************/ + + +/* List of all wanpipe sockets. */ +struct sock * wanpipe_sklist = NULL; +static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED; + +atomic_t wanpipe_socks_nr; +static unsigned long wanpipe_tx_critical=0; + +#if 0 +/* Private wanpipe socket structures. */ +struct wanpipe_opt +{ + void *mbox; /* Mail box */ + void *card; /* Card bouded to */ + netdevice_t *dev; /* Bounded device */ + unsigned short lcn; /* Binded LCN */ + unsigned char svc; /* 0=pvc, 1=svc */ + unsigned char timer; /* flag for delayed transmit*/ + struct timer_list tx_timer; + unsigned poll_cnt; + unsigned char force; /* Used to force sock release */ + atomic_t packet_sent; +}; +#endif + +static int sk_count=0; +extern struct proto_ops wanpipe_ops; +static unsigned long find_free_critical=0; + +static void wanpipe_unlink_driver (struct sock *); +static void wanpipe_link_driver (netdevice_t *,struct sock *sk); +static void wanpipe_wakeup_driver(struct sock *sk); +static int execute_command(struct sock *, unsigned char, unsigned int); +static int check_dev (netdevice_t *, sdla_t *); +netdevice_t * wanpipe_find_free_dev (sdla_t *); +static void wanpipe_unlink_card (struct sock *); +static int wanpipe_link_card (struct sock *); +static struct sock *wanpipe_make_new(struct sock *); +static struct sock *wanpipe_alloc_socket(void); +static inline int get_atomic_device (netdevice_t *); +static int wanpipe_exec_cmd(struct sock *, int, unsigned int); +static int get_ioctl_cmd (struct sock *, void *); +static int set_ioctl_cmd (struct sock *, void *); +static void release_device (netdevice_t *); +static void wanpipe_kill_sock_timer (unsigned long data); +static void wanpipe_kill_sock_irq (struct sock *); +static void wanpipe_kill_sock_accept (struct sock *); +static int wanpipe_do_bind(struct sock *, netdevice_t *, int); +struct sock * get_newsk_from_skb (struct sk_buff *); +static int wanpipe_debug (struct sock *, void *); +static void wanpipe_delayed_transmit (unsigned long data); +static void release_driver(struct sock *); +static void start_cleanup_timer (struct sock *); +static void check_write_queue(struct sock *); +static int check_driver_busy (struct sock *); + +/*============================================================ + * wanpipe_rcv + * + * Wanpipe socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue a + * incomming packet into the socket receive queue. + * Once the packet is queued, all processes waiting to + * read are woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + *===========================================================*/ + +static int wanpipe_rcv(struct sk_buff *skb, netdevice_t *dev, struct sock *sk) +{ + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; + wanpipe_common_t *chan = dev->priv; + /* + * When we registered the protocol we saved the socket in the data + * field for just this event. + */ + + skb->dev = dev; + + sll->sll_family = AF_WANPIPE; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + + /* + * WAN_PACKET_DATA : Data which should be passed up the receive queue. + * WAN_PACKET_ASYC : Asynchronous data like place call, which should + * be passed up the listening sock. + * WAN_PACKET_ERR : Asynchronous data like clear call or restart + * which should go into an error queue. + */ + switch (skb->pkt_type){ + + case WAN_PACKET_DATA: + if (sock_queue_rcv_skb(sk,skb)<0){ + return -ENOMEM; + } + break; + case WAN_PACKET_CMD: + sk->state = chan->state; + /* Bug fix: update Mar6. + * Do not set the sock lcn number here, since + * cmd is not guaranteed to be executed on the + * board, thus Lcn could be wrong */ + sk->data_ready(sk,skb->len); + kfree_skb(skb); + break; + case WAN_PACKET_ERR: + sk->state = chan->state; + if (sock_queue_err_skb(sk,skb)<0){ + return -ENOMEM; + } + break; + default: + printk(KERN_INFO "wansock: BH Illegal Packet Type Dropping\n"); + kfree_skb(skb); + break; + } + +//?????????????????????? +// if (sk->state == WANSOCK_DISCONNECTED){ +// if (sk->zapped){ +// //printk(KERN_INFO "wansock: Disconnected, killing early\n"); +// wanpipe_unlink_driver(sk); +// sk->bound_dev_if = 0; +// } +// } + + return 0; +} + +/*============================================================ + * wanpipe_listen_rcv + * + * Wanpipe LISTEN socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue an + * incomming call into the socket listening queue. + * Once the packet is queued, the waiting accept() process + * is woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + * + * IMPORTANT NOTE: + * The accept call() is waiting for an skb packet + * which contains a pointer to a device structure. + * + * When we do a bind to a device structre, we + * bind a newly created socket into "chan->sk". Thus, + * when accept receives the skb packet, it will know + * from which dev it came form, and in turn it will know + * the address of the new sock. + * + * NOTE: This function gets called from driver ISR. + *===========================================================*/ + +static int wanpipe_listen_rcv (struct sk_buff *skb, struct sock *sk) +{ + + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; + struct sock *newsk; + netdevice_t *dev; + sdla_t *card; + mbox_cmd_t *mbox_ptr; + wanpipe_common_t *chan; + + /* Find a free device, if none found, all svc's are busy + */ + + card = (sdla_t*)sk->protinfo.af_wanpipe->card; + if (!card){ + printk(KERN_INFO "wansock: LISTEN ERROR, No Card\n"); + return -ENODEV; + } + + dev = wanpipe_find_free_dev(card); + if (!dev){ + printk(KERN_INFO "wansock: LISTEN ERROR, No Free Device\n"); + return -ENODEV; + } + + chan=dev->priv; + chan->state = WANSOCK_CONNECTING; + + /* Allocate a new sock, which accept will bind + * and pass up to the user + */ + if ((newsk = wanpipe_make_new(sk)) == NULL){ + release_device(dev); + return -ENOMEM; + } + + + /* Initialize the new sock structure + */ + newsk->bound_dev_if = dev->ifindex; + newsk->protinfo.af_wanpipe->card = sk->protinfo.af_wanpipe->card; + + /* Insert the sock into the main wanpipe + * sock list. + */ + atomic_inc(&wanpipe_socks_nr); + + /* Allocate and fill in the new Mail Box. Then + * bind the mail box to the sock. It will be + * used by the ioctl call to read call information + * and to execute commands. + */ + if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) { + wanpipe_kill_sock_irq (newsk); + release_device(dev); + return -ENOMEM; + } + memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); + memcpy(mbox_ptr,skb->data,skb->len); + + /* Register the lcn on which incoming call came + * from. Thus, if we have to clear it, we know + * whic lcn to clear + */ + + newsk->protinfo.af_wanpipe->lcn = mbox_ptr->cmd.lcn; + newsk->protinfo.af_wanpipe->mbox = (void *)mbox_ptr; + + DBG_PRINTK(KERN_INFO "NEWSOCK : Device %s, bind to lcn %i\n", + dev->name,mbox_ptr->cmd.lcn); + + chan->lcn = mbox_ptr->cmd.lcn; + card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev; + + newsk->zapped=0; + newsk->num = htons(X25_PROT); + + if (wanpipe_do_bind(newsk,dev,newsk->num)){ + wanpipe_kill_sock_irq (newsk); + release_device(dev); + return -EINVAL; + } + newsk->state = WANSOCK_CONNECTING; + + + /* Fill in the standard sock address info */ + + sll->sll_family = AF_WANPIPE; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + skb->dev = dev; + sk->ack_backlog++; + + /* We must do this manually, since the sock_queue_rcv_skb() + * function sets the skb->dev to NULL. However, we use + * the dev field in the accept function.*/ + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= + (unsigned)sk->rcvbuf){ + + wanpipe_unlink_driver(newsk); + wanpipe_kill_sock_irq (newsk); + --sk->ack_backlog; + return -ENOMEM; + } + + skb_set_owner_r(skb, sk); + skb_queue_tail(&sk->receive_queue, skb); + sk->data_ready(sk,skb->len); + + return 0; +} + + + +/*============================================================ + * wanpipe_make_new + * + * Create a new sock, and allocate a wanpipe private + * structure to it. Also, copy the important data + * from the original sock to the new sock. + * + * This function is used by wanpipe_listen_rcv() listen + * bottom half handler. A copy of the listening sock + * is created using this function. + * + *===========================================================*/ + +static struct sock *wanpipe_make_new(struct sock *osk) +{ + struct sock *sk; + + if (osk->type != SOCK_RAW) + return NULL; + + if ((sk = wanpipe_alloc_socket()) == NULL) + return NULL; + + sk->type = osk->type; + sk->socket = osk->socket; + sk->priority = osk->priority; + sk->protocol = osk->protocol; + sk->num = osk->num; + sk->rcvbuf = osk->rcvbuf; + sk->sndbuf = osk->sndbuf; + sk->debug = osk->debug; + sk->state = WANSOCK_CONNECTING; + sk->sleep = osk->sleep; + + return sk; +} + +/*============================================================ + * wanpipe_make_new + * + * Allocate memory for the a new sock, and sock + * private data. + * + * Increment the module use count. + * + * This function is used by wanpipe_create() and + * wanpipe_make_new() functions. + * + *===========================================================*/ + +static struct sock *wanpipe_alloc_socket(void) +{ + struct sock *sk; + struct wanpipe_opt *wan_opt; + + if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1)) == NULL) + return NULL; + + if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) { + sk_free(sk); + return NULL; + } + memset(wan_opt, 0x00, sizeof(struct wanpipe_opt)); + + sk->protinfo.af_wanpipe = wan_opt; + sk->protinfo.destruct_hook = wan_opt; + + /* Use timer to send data to the driver. This will act + * as a BH handler for sendmsg functions */ + sk->protinfo.af_wanpipe->tx_timer.data=(unsigned long)sk; + sk->protinfo.af_wanpipe->tx_timer.function=wanpipe_delayed_transmit; + + MOD_INC_USE_COUNT; + + sock_init_data(NULL, sk); + return sk; +} + + +/*============================================================ + * wanpipe_sendmsg + * + * This function implements a sendto() system call, + * for AF_WANPIPE socket family. + * During socket bind() sk->bound_dev_if is initialized + * to a correct network device. This number is used + * to find a network device to which the packet should + * be passed to. + * + * Each packet is queued into sk->write_queue and + * delayed transmit bottom half handler is marked for + * execution. + * + * A socket must be in WANSOCK_CONNECTED state before + * a packet is queued into sk->write_queue. + *===========================================================*/ + +static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name; + struct sk_buff *skb; + netdevice_t *dev; + unsigned short proto; + unsigned char *addr; + int ifindex, err, reserve = 0; + + + if (!sk->zapped) + return -ENETDOWN; + + if (sk->state != WANSOCK_CONNECTED) + return -ENOTCONN; + + if (msg->msg_flags&~MSG_DONTWAIT) + return(-EINVAL); + + /* it was <=, now one can send + * zero length packets */ + if (len < sizeof(x25api_hdr_t)) + return -EINVAL; + + if (saddr == NULL) { + ifindex = sk->bound_dev_if; + proto = sk->num; + addr = NULL; + + }else{ + if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ + return -EINVAL; + } + + ifindex = sk->bound_dev_if; + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + } + + dev = dev_get_by_index(ifindex); + if (dev == NULL){ + printk(KERN_INFO "wansock: Send failed, dev index: %i\n",ifindex); + return -ENXIO; + } + dev_put(dev); + + if (sock->type == SOCK_RAW) + reserve = dev->hard_header_len; + + if (len > dev->mtu+reserve){ + return -EMSGSIZE; + } + + #ifndef LINUX_2_4 + dev_lock_list(); + #endif + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, + msg->msg_flags & MSG_DONTWAIT, &err); + #else + skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, + msg->msg_flags & MSG_DONTWAIT, &err); + #endif + + if (skb==NULL){ + goto out_unlock; + } + + skb_reserve(skb, (dev->hard_header_len+15)&~15); + skb->nh.raw = skb->data; + + /* Returns -EFAULT on error */ + err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + if (err){ + goto out_free; + } + + if (dev->hard_header) { + int res; + err = -EINVAL; + res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); + if (res<0){ + goto out_free; + } + } + + skb->protocol = proto; + skb->dev = dev; + skb->priority = sk->priority; + skb->pkt_type = WAN_PACKET_DATA; + + err = -ENETDOWN; + if (!(dev->flags & IFF_UP)) + goto out_free; + + #ifndef LINUX_2_4 + dev_unlock_list(); + #endif + + if (atomic_read(&sk->wmem_alloc) + skb->truesize > (unsigned int)sk->sndbuf){ + kfree_skb(skb); + return -ENOBUFS; + } + + skb_queue_tail(&sk->write_queue,skb); + atomic_inc(&sk->protinfo.af_wanpipe->packet_sent); + + if (!(test_and_set_bit(0,&sk->protinfo.af_wanpipe->timer))){ + del_timer(&sk->protinfo.af_wanpipe->tx_timer); + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + } + + return(len); + +out_free: + kfree_skb(skb); +out_unlock: +#ifndef LINUX_2_4 + dev_unlock_list(); +#endif + return err; +} + +/*============================================================ + * wanpipe_delayed_tarnsmit + * + * Transmit bottom half handeler. It dequeues packets + * from sk->write_queue and passes them to the + * driver. If the driver is busy, the packet is + * re-enqueued. + * + * Packet Sent counter is decremented on successful + * transmission. + *===========================================================*/ + + +static void wanpipe_delayed_transmit (unsigned long data) +{ + struct sock *sk=(struct sock *)data; + struct sk_buff *skb; + netdevice_t *dev = sk->protinfo.af_wanpipe->dev; + sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card; + + if (!card || !dev){ + clear_bit (0,&sk->protinfo.af_wanpipe->timer); + DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n"); + return; + } + + if (sk->state != WANSOCK_CONNECTED || !sk->zapped){ + clear_bit (0,&sk->protinfo.af_wanpipe->timer); + DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n"); + return; + } + + /* If driver is executing command, we must offload + * the board by not sending data. Otherwise a + * pending command will never get a free buffer + * to execute */ + if (atomic_read(&card->u.x.command_busy)){ + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + DBG_PRINTK(KERN_INFO "wansock: Tx Timer, command bys BACKOFF\n"); + return; + } + + + if (test_and_set_bit(0,&wanpipe_tx_critical)){ + printk(KERN_INFO "WanSock: Tx timer critical %s\n",dev->name); + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + return; + } + + /* Check for a packet in the fifo and send */ + if ((skb=skb_dequeue(&sk->write_queue)) != NULL){ + + if (dev->hard_start_xmit(skb, dev) != 0){ + + /* Driver failed to transmit, re-enqueue + * the packet and retry again later */ + skb_queue_head(&sk->write_queue,skb); + clear_bit(0,&wanpipe_tx_critical); + return; + }else{ + + /* Packet Sent successful. Check for more packets + * if more packets, re-trigger the transmit routine + * other wise exit + */ + atomic_dec(&sk->protinfo.af_wanpipe->packet_sent); + + if (skb_peek(&sk->write_queue) == NULL){ + /* If there is nothing to send, kick + * the poll routine, which will trigger + * the application to send more data */ + sk->data_ready(sk,0); + clear_bit (0,&sk->protinfo.af_wanpipe->timer); + }else{ + /* Reschedule as fast as possible */ + sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1; + add_timer(&sk->protinfo.af_wanpipe->tx_timer); + } + } + } + clear_bit(0,&wanpipe_tx_critical); +} + +/*============================================================ + * execute_command + * + * Execute x25api commands. The atomic variable + * chan->command is used to indicate to the driver that + * command is pending for exection. The acutal command + * structure is placed into a sock mbox structure + * (sk->protinfo.af_wanpipe->mbox). + * + * The sock private structure, mbox is + * used as shared memory between sock and the driver. + * Driver uses the sock mbox to execute the command + * and return the result. + * + * For all command except PLACE CALL, the function + * waits for the result. PLACE CALL can be ether + * blocking or nonblocking. The user sets this option + * via ioctl call. + *===========================================================*/ + + +static int execute_command(struct sock *sk, unsigned char cmd, unsigned int flags) +{ + netdevice_t *dev; + wanpipe_common_t *chan=NULL; + int err=0; + DECLARE_WAITQUEUE(wait, current); + + dev = dev_get_by_index(sk->bound_dev_if); + if (dev == NULL){ + printk(KERN_INFO "wansock: Exec failed no dev %i\n", + sk->bound_dev_if); + return -ENODEV; + } + dev_put(dev); + + if ((chan=dev->priv) == NULL){ + printk(KERN_INFO "wansock: Exec cmd failed no priv area\n"); + return -ENODEV; + } + + if (atomic_read(&chan->command)){ + printk(KERN_INFO "wansock: ERROR: Command already running %x, %s\n", + atomic_read(&chan->command),dev->name); + return -EINVAL; + } + + if (!sk->protinfo.af_wanpipe->mbox){ + printk(KERN_INFO "wansock: In execute without MBOX\n"); + return -EINVAL; + } + + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.command=cmd; + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn = + sk->protinfo.af_wanpipe->lcn; + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result=0x7F; + + + if (flags & O_NONBLOCK){ + cmd |= 0x80; + atomic_set(&chan->command, cmd); + }else{ + atomic_set(&chan->command, cmd); + } + + add_wait_queue(sk->sleep,&wait); + current->state = TASK_INTERRUPTIBLE; + for (;;){ + if (((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result != 0x7F) { + err = 0; + break; + } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep,&wait); + + return err; +} + +/*============================================================ + * wanpipe_destroy_timer + * + * Used by wanpipe_release, to delay release of + * the socket. + *===========================================================*/ + +static void wanpipe_destroy_timer(unsigned long data) +{ + struct sock *sk=(struct sock *)data; + + if ((!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) || + (++sk->protinfo.af_wanpipe->force == 5)) { + + if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) + printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n"); + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; + } + + sk->timer.expires=jiffies+5*HZ; + add_timer(&sk->timer); + printk(KERN_INFO "wansock: packet sk destroy delayed\n"); +} + +/*============================================================ + * wanpipe_unlink_driver + * + * When the socket is released, this function is + * used to remove links that bind the sock and the + * driver together. + *===========================================================*/ +static void wanpipe_unlink_driver (struct sock *sk) +{ + netdevice_t *dev; + wanpipe_common_t *chan=NULL; + + sk->zapped=0; + sk->state = WANSOCK_DISCONNECTED; + sk->protinfo.af_wanpipe->dev = NULL; + + dev = dev_get_by_index(sk->bound_dev_if); + if (!dev){ + printk(KERN_INFO "wansock: No dev on release\n"); + return; + } + dev_put(dev); + + if ((chan = dev->priv) == NULL){ + printk(KERN_INFO "wansock: No Priv Area on release\n"); + return; + } + + set_bit(0,&chan->common_critical); + chan->sk=NULL; + chan->func=NULL; + chan->mbox=NULL; + chan->tx_timer=NULL; + clear_bit(0,&chan->common_critical); + release_device(dev); + + return; +} + +/*============================================================ + * wanpipe_link_driver + * + * Upon successful bind(), sock is linked to a driver + * by binding in the wanpipe_rcv() bottom half handler + * to the driver function pointer, as well as sock and + * sock mailbox addresses. This way driver can pass + * data up the socket. + *===========================================================*/ + +static void wanpipe_link_driver (netdevice_t *dev, struct sock *sk) +{ + wanpipe_common_t *chan = dev->priv; + if (!chan) + return; + set_bit(0,&chan->common_critical); + chan->sk=sk; + chan->func=wanpipe_rcv; + chan->mbox=sk->protinfo.af_wanpipe->mbox; + chan->tx_timer = &sk->protinfo.af_wanpipe->tx_timer; + sk->protinfo.af_wanpipe->dev=dev; + sk->zapped = 1; + clear_bit(0,&chan->common_critical); +} + + +/*============================================================ + * release_device + * + * During sock release, clear a critical bit, which + * marks the device a being taken. + *===========================================================*/ + + +static void release_device (netdevice_t *dev) +{ + wanpipe_common_t *chan=dev->priv; + clear_bit(0,(void*)&chan->rw_bind); +} + +/*============================================================ + * wanpipe_release + * + * Close a PACKET socket. This is fairly simple. We + * immediately go to 'closed' state and remove our + * protocol entry in the device list. + *===========================================================*/ + +#ifdef LINUX_2_4 +static int wanpipe_release(struct socket *sock) +#else +static int wanpipe_release(struct socket *sock, struct socket *peersock) +#endif +{ + +#ifndef LINUX_2_4 + struct sk_buff *skb; +#endif + struct sock *sk = sock->sk; + struct sock **skp; + + if (!sk) + return 0; + + check_write_queue(sk); + + /* Kill the tx timer, if we don't kill it now, the timer + * will run after we kill the sock. Timer code will + * try to access the sock which has been killed and cause + * kernel panic */ + + del_timer(&sk->protinfo.af_wanpipe->tx_timer); + + /* + * Unhook packet receive handler. + */ + + if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->zapped){ + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + wanpipe_common_t *chan; + if (dev){ + chan=dev->priv; + atomic_set(&chan->disconnect,1); + DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n", + sk->state); + dev_put(dev); + } + } + + set_bit(1,&wanpipe_tx_critical); + write_lock(&wanpipe_sklist_lock); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock(&wanpipe_sklist_lock); + clear_bit(1,&wanpipe_tx_critical); + + + + release_driver(sk); + + + /* + * Now the socket is dead. No more input will appear. + */ + + sk->state_change(sk); /* It is useless. Just for sanity. */ + + sock->sk = NULL; + sk->socket = NULL; + sk->dead = 1; + + /* Purge queues */ +#ifdef LINUX_2_4 + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->error_queue); +#else + + while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->error_queue))!=NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->write_queue))!=NULL){ + kfree_skb(skb); + } +#endif + if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { + del_timer(&sk->timer); + printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n", + atomic_read(&sk->rmem_alloc),atomic_read(&sk->wmem_alloc)); + sk->timer.data=(unsigned long)sk; + sk->timer.expires=jiffies+HZ; + sk->timer.function=wanpipe_destroy_timer; + add_timer(&sk->timer); + return 0; + } + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n", + atomic_read(&sk->refcnt)); + atomic_set(&sk->refcnt,1); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return 0; +} + +/*============================================================ + * check_write_queue + * + * During sock shutdown, if the sock state is + * WANSOCK_CONNECTED and there is transmit data + * pending. Wait until data is released + * before proceeding. + *===========================================================*/ + +static void check_write_queue(struct sock *sk) +{ + + if (sk->state != WANSOCK_CONNECTED) + return; + + if (!atomic_read(&sk->wmem_alloc)) + return; + + printk(KERN_INFO "wansock: MAJOR ERROR, Data lost on sock release !!!\n"); + +} + +/*============================================================ + * release_driver + * + * This function is called during sock shutdown, to + * release any resources and links that bind the sock + * to the driver. It also changes the state of the + * sock to WANSOCK_DISCONNECTED + *===========================================================*/ + +static void release_driver(struct sock *sk) +{ + struct sk_buff *skb=NULL; + struct sock *deadsk=NULL; + + if (sk->state == WANSOCK_LISTEN || sk->state == WANSOCK_BIND_LISTEN){ + while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ + if ((deadsk = get_newsk_from_skb(skb))){ + DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n"); + deadsk->dead=1; + start_cleanup_timer(deadsk); + } + kfree_skb(skb); + } + if (sk->zapped) + wanpipe_unlink_card(sk); + }else{ + if (sk->zapped) + wanpipe_unlink_driver(sk); + } + sk->state = WANSOCK_DISCONNECTED; + sk->bound_dev_if = 0; + sk->zapped=0; + + if (sk->protinfo.af_wanpipe){ + if (sk->protinfo.af_wanpipe->mbox){ + kfree(sk->protinfo.af_wanpipe->mbox); + sk->protinfo.af_wanpipe->mbox=NULL; + } + } +} + +/*============================================================ + * start_cleanup_timer + * + * If new incoming call's are pending but the socket + * is being released, start the timer which will + * envoke the kill routines for pending socks. + *===========================================================*/ + + +static void start_cleanup_timer (struct sock *sk) +{ + del_timer(&sk->timer); + sk->timer.data = (unsigned long)sk; + sk->timer.expires = jiffies + HZ; + sk->timer.function = wanpipe_kill_sock_timer; + add_timer(&sk->timer); +} + + +/*============================================================ + * wanpipe_kill_sock + * + * This is a function which performs actual killing + * of the sock. It releases socket resources, + * and unlinks the sock from the driver. + *===========================================================*/ + +static void wanpipe_kill_sock_timer (unsigned long data) +{ + + struct sock *sk = (struct sock *)data; +#ifndef LINUX_2_4 + struct sk_buff *skb; +#endif + + struct sock **skp; + + if (!sk) + return; + + /* This functin can be called from interrupt. We must use + * appropriate locks */ + + if (test_bit(1,&wanpipe_tx_critical)){ + sk->timer.expires=jiffies+10; + add_timer(&sk->timer); + return; + } + + write_lock(&wanpipe_sklist_lock); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock(&wanpipe_sklist_lock); + + + if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED){ + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + wanpipe_common_t *chan; + if (dev){ + chan=dev->priv; + atomic_set(&chan->disconnect,1); + dev_put(dev); + } + } + + release_driver(sk); + + sk->socket = NULL; + + /* Purge queues */ +#ifdef LINUX_2_4 + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->error_queue); +#else + while ((skb=skb_dequeue(&sk->receive_queue)) != NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->write_queue)) != NULL) { + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->error_queue)) != NULL){ + kfree_skb(skb); + } +#endif + + if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { + del_timer(&sk->timer); + printk(KERN_INFO "wansock: Killing SOCK in Timer\n"); + sk->timer.data=(unsigned long)sk; + sk->timer.expires=jiffies+HZ; + sk->timer.function=wanpipe_destroy_timer; + add_timer(&sk->timer); + return; + } + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + +static void wanpipe_kill_sock_accept (struct sock *sk) +{ + + struct sock **skp; + + if (!sk) + return; + + /* This functin can be called from interrupt. We must use + * appropriate locks */ + + write_lock(&wanpipe_sklist_lock); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock(&wanpipe_sklist_lock); + + sk->socket = NULL; + + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + + +static void wanpipe_kill_sock_irq (struct sock *sk) +{ + + if (!sk) + return; + + sk->socket = NULL; + + if (sk->protinfo.af_wanpipe){ + kfree(sk->protinfo.af_wanpipe); + sk->protinfo.af_wanpipe=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:listen.\n", + atomic_read(&sk->refcnt)); + } + sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + + +/*============================================================ + * wanpipe_do_bind + * + * Bottom half of the binding system call. + * Once the wanpipe_bind() function checks the + * legality of the call, this function binds the + * sock to the driver. + *===========================================================*/ + +static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol) +{ + wanpipe_common_t *chan=NULL; + int err=0; + + if (sk->zapped){ + err = -EALREADY; + goto bind_unlock_exit; + } + + sk->num = protocol; + + if (protocol == 0){ + release_device(dev); + err = -EINVAL; + goto bind_unlock_exit; + } + + if (dev) { + if (dev->flags&IFF_UP) { + chan=dev->priv; + sk->state = chan->state; + + if (sk->num == htons(X25_PROT) && + sk->state != WANSOCK_DISCONNECTED && + sk->state != WANSOCK_CONNECTING){ + DBG_PRINTK(KERN_INFO + "wansock: Binding to Device not DISCONNECTED %i\n", + sk->state); + release_device(dev); + err = -EAGAIN; + goto bind_unlock_exit; + } + + wanpipe_link_driver(dev,sk); + sk->bound_dev_if = dev->ifindex; + + /* X25 Specific option */ + if (sk->num == htons(X25_PROT)) + sk->protinfo.af_wanpipe->svc = chan->svc; + + } else { + sk->err = ENETDOWN; + sk->error_report(sk); + release_device(dev); + err = -EINVAL; + } + } else { + err = -ENODEV; + } +bind_unlock_exit: + /* FIXME where is this lock */ + + return err; +} + +/*============================================================ + * wanpipe_bind + * + * BIND() System call, which is bound to the AF_WANPIPE + * operations structure. It checks for correct wanpipe + * card name, and cross references interface names with + * the card names. Thus, interface name must belong to + * the actual card. + *===========================================================*/ + + +static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; + struct sock *sk=sock->sk; + netdevice_t *dev = NULL; + sdla_t *card=NULL; + char name[15]; + + /* + * Check legality + */ + + if (addr_len < sizeof(struct wan_sockaddr_ll)){ + printk(KERN_INFO "wansock: Address length error\n"); + return -EINVAL; + } + if (sll->sll_family != AF_WANPIPE){ + printk(KERN_INFO "wansock: Illegal family name specified.\n"); + return -EINVAL; + } + + card = wanpipe_find_card (sll->sll_card); + if (!card){ + printk(KERN_INFO "wansock: Wanpipe card not found: %s\n",sll->sll_card); + return -ENODEV; + }else{ + sk->protinfo.af_wanpipe->card = (void *)card; + } + + if (!strcmp(sll->sll_device,"svc_listen")){ + + /* Bind a sock to a card structure for listening + */ + int err=0; + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sll->sll_protocol != htons(X25_PROT)) + return -EINVAL; + + err= wanpipe_link_card (sk); + if (err < 0) + return err; + + if (sll->sll_protocol) + sk->num = sll->sll_protocol; + sk->state = WANSOCK_BIND_LISTEN; + return 0; + + }else if (!strcmp(sll->sll_device,"svc_connect")){ + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sll->sll_protocol != htons(X25_PROT)) + return -EINVAL; + + /* Find a free device + */ + dev = wanpipe_find_free_dev(card); + if (dev == NULL){ + DBG_PRINTK(KERN_INFO "wansock: No free network devices for card %s\n", + card->devname); + return -EINVAL; + } + }else{ + /* Bind a socket to a interface name + * This is used by PVC mostly + */ + strncpy(name,sll->sll_device,14); + name[14]=0; +#ifdef LINUX_2_4 + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ + printk(KERN_INFO "wansock: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } + + dev_put(dev); + + if (check_dev(dev, card)){ + printk(KERN_INFO "wansock: Device %s, doesn't belong to card %s\n", + dev->name, card->devname); + return -EINVAL; + } + if (get_atomic_device (dev)) + return -EINVAL; + } + + return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : sk->num); +} + +/*============================================================ + * get_atomic_device + * + * Sets a bit atomically which indicates that + * the interface is taken. This avoids race conditions. + *===========================================================*/ + + +static inline int get_atomic_device (netdevice_t *dev) +{ + wanpipe_common_t *chan = dev->priv; + if (!test_and_set_bit(0,(void *)&chan->rw_bind)){ + return 0; + } + return 1; +} + +/*============================================================ + * check_dev + * + * Check that device name belongs to a particular card. + *===========================================================*/ + +static int check_dev (netdevice_t *dev, sdla_t *card) +{ + netdevice_t* tmp_dev; + + for (tmp_dev = card->wandev.dev; tmp_dev; tmp_dev=*((netdevice_t**)tmp_dev->priv)){ + if (tmp_dev->ifindex == dev->ifindex){ + return 0; + } + } + return 1; +} + +/*============================================================ + * wanpipe_find_free_dev + * + * Find a free network interface. If found set atomic + * bit indicating that the interface is taken. + * X25API Specific. + *===========================================================*/ + +netdevice_t * wanpipe_find_free_dev (sdla_t *card) +{ + netdevice_t* dev; + volatile wanpipe_common_t *chan; + + if (test_and_set_bit(0,&find_free_critical)){ + printk(KERN_INFO "CRITICAL in Find Free\n"); + } + + for (dev = card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){ + chan = dev->priv; + if (!chan) + continue; + if (chan->usedby == API && chan->svc){ + if (!get_atomic_device (dev)){ + if (chan->state != WANSOCK_DISCONNECTED){ + release_device(dev); + }else{ + clear_bit(0,&find_free_critical); + return dev; + } + } + } + } + clear_bit(0,&find_free_critical); + return NULL; +} + +/*============================================================ + * wanpipe_create + * + * SOCKET() System call. It allocates a sock structure + * and adds the socket to the wanpipe_sk_list. + * Crates AF_WANPIPE socket. + *===========================================================*/ + +static int wanpipe_create(struct socket *sock, int protocol) +{ + struct sock *sk; + + //FIXME: This checks for root user, SECURITY ? + //if (!capable(CAP_NET_RAW)) + // return -EPERM; + + if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + + sock->state = SS_UNCONNECTED; + + if ((sk = wanpipe_alloc_socket()) == NULL) + return -ENOBUFS; + + sk->reuse = 1; + sock->ops = &wanpipe_ops; + sock_init_data(sock,sk); + + sk->zapped=0; + sk->family = PF_WANPIPE; + sk->num = protocol; + sk->state = WANSOCK_DISCONNECTED; + sk->ack_backlog = 0; + sk->bound_dev_if=0; + + atomic_inc(&wanpipe_socks_nr); + + /* We must disable interrupts because the ISR + * can also change the list */ + set_bit(1,&wanpipe_tx_critical); + write_lock(&wanpipe_sklist_lock); + sk->next = wanpipe_sklist; + wanpipe_sklist = sk; + sock_hold(sk); + write_unlock(&wanpipe_sklist_lock); + clear_bit(1,&wanpipe_tx_critical); + + return(0); +} + + +/*============================================================ + * wanpipe_recvmsg + * + * Pull a packet from our receive queue and hand it + * to the user. If necessary we block. + *===========================================================*/ + +static int wanpipe_recvmsg(struct socket *sock, struct msghdr *msg, int len, + int flags, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err=-ENOBUFS; + + + /* + * If the address length field is there to be filled in, we fill + * it in now. + */ + + msg->msg_namelen = sizeof(struct wan_sockaddr_ll); + + /* + * Call the generic datagram receiver. This handles all sorts + * of horrible races and re-entrancy so we can forget about it + * in the protocol layers. + * + * Now it will return ENETDOWN, if device have just gone down, + * but then it will block. + */ + + if (flags & MSG_OOB){ + skb=skb_dequeue(&sk->error_queue); + }else{ + skb=skb_recv_datagram(sk,flags,1,&err); + } + /* + * An error occurred so return it. Because skb_recv_datagram() + * handles the blocking we don't see and worry about blocking + * retries. + */ + + if(skb==NULL) + goto out; + + /* + * You lose any data beyond the buffer you gave. If it worries a + * user program they can ask the device for its MTU anyway. + */ + + copied = skb->len; + if (copied > len) + { + copied=len; + msg->msg_flags|=MSG_TRUNC; + } + + wanpipe_wakeup_driver(sk); + + /* We can't use skb_copy_datagram here */ + err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + if (err) + goto out_free; + +#ifdef LINUX_2_1 + sk->stamp=skb->stamp; +#else + sock_recv_timestamp(msg, sk, skb); +#endif + + if (msg->msg_name) + memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + + /* + * Free or return the buffer as appropriate. Again this + * hides all the races and re-entrancy issues from us. + */ + err = (flags&MSG_TRUNC) ? skb->len : copied; + +out_free: + skb_free_datagram(sk, skb); +out: + return err; +} + + +/*============================================================ + * wanpipe_wakeup_driver + * + * If socket receive buffer is full and driver cannot + * pass data up the sock, it sets a packet_block flag. + * This function check that flag and if sock receive + * queue has room it kicks the driver BH handler. + * + * This way, driver doesn't have to poll the sock + * receive queue. + *===========================================================*/ + +static void wanpipe_wakeup_driver(struct sock *sk) +{ + netdevice_t *dev=NULL; + wanpipe_common_t *chan=NULL; + + dev = dev_get_by_index(sk->bound_dev_if); + if (!dev) + return; + + dev_put(dev); + + if ((chan = dev->priv) == NULL) + return; + + if (atomic_read(&chan->receive_block)){ + if (atomic_read(&sk->rmem_alloc) < ((unsigned)sk->rcvbuf*0.9) ){ + printk(KERN_INFO "wansock: Queuing task for wanpipe\n"); + atomic_set(&chan->receive_block,0); + wanpipe_queue_tq(&chan->wanpipe_task); + wanpipe_mark_bh(); + } + } +} + +/*============================================================ + * wanpipe_getname + * + * I don't know what to do with this yet. + * User can use this function to get sock address + * information. Not very useful for Sangoma's purposes. + *===========================================================*/ + + +static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + netdevice_t *dev; + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; + + sll->sll_family = AF_WANPIPE; + sll->sll_ifindex = sk->bound_dev_if; + sll->sll_protocol = sk->num; + dev = dev_get_by_index(sk->bound_dev_if); + if (dev) { + sll->sll_hatype = dev->type; + sll->sll_halen = dev->addr_len; + memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); + } else { + sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ + sll->sll_halen = 0; + } + *uaddr_len = sizeof(*sll); + + dev_put(dev); + + return 0; +} + +/*============================================================ + * wanpipe_notifier + * + * If driver turns off network interface, this function + * will be envoked. Currently I treate it as a + * call disconnect. More thought should go into this + * function. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data) +{ + struct sock *sk; + netdevice_t *dev = (netdevice_t*)data; + struct wanpipe_opt *po; + + for (sk = wanpipe_sklist; sk; sk = sk->next) { + + if ((po = sk->protinfo.af_wanpipe)==NULL) + continue; + if (dev == NULL) + continue; + + switch (msg) { + case NETDEV_DOWN: + case NETDEV_UNREGISTER: + if (dev->ifindex == sk->bound_dev_if) { + printk(KERN_INFO "wansock: Device down %s\n",dev->name); + if (sk->zapped){ + wanpipe_unlink_driver(sk); + sk->err = ENETDOWN; + sk->error_report(sk); + } + + if (msg == NETDEV_UNREGISTER) { + printk(KERN_INFO "wansock: Unregistering Device: %s\n", + dev->name); + wanpipe_unlink_driver(sk); + sk->bound_dev_if = 0; + } + } + break; + case NETDEV_UP: + if (dev->ifindex == sk->bound_dev_if && sk->num && !sk->zapped) { + printk(KERN_INFO "wansock: Registering Device: %s\n", + dev->name); + wanpipe_link_driver(dev,sk); + } + break; + } + } + return NOTIFY_DONE; +} + +/*============================================================ + * wanpipe_ioctl + * + * Execute a user commands, and set socket options. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + int err; + int pid; + + switch(cmd) + { + case FIOSETOWN: + case SIOCSPGRP: + err = get_user(pid, (int *) arg); + if (err) + return err; + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) + return -EPERM; + sk->proc = pid; + return(0); + case FIOGETOWN: + case SIOCGPGRP: + return put_user(sk->proc, (int *)arg); + case SIOCGSTAMP: + if(sk->stamp.tv_sec==0) + return -ENOENT; + err = -EFAULT; + if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) + err = 0; + return err; + + case SIOC_WANPIPE_CHECK_TX: + + return atomic_read(&sk->wmem_alloc); + + case SIOC_WANPIPE_SOCK_STATE: + + if (sk->state == WANSOCK_CONNECTED) + return 0; + + return 1; + + + case SIOC_WANPIPE_GET_CALL_DATA: + + return get_ioctl_cmd (sk,(void*)arg); + + case SIOC_WANPIPE_SET_CALL_DATA: + + return set_ioctl_cmd (sk,(void*)arg); + + case SIOC_WANPIPE_ACCEPT_CALL: + case SIOC_WANPIPE_CLEAR_CALL: + case SIOC_WANPIPE_RESET_CALL: + + if ((err=set_ioctl_cmd(sk,(void*)arg)) < 0) + return err; + + err=wanpipe_exec_cmd(sk,cmd,0); + get_ioctl_cmd(sk,(void*)arg); + return err; + + case SIOC_WANPIPE_DEBUG: + + return wanpipe_debug(sk,(void*)arg); + + case SIOC_WANPIPE_SET_NONBLOCK: + + if (sk->state != WANSOCK_DISCONNECTED) + return -EINVAL; + + sock->file->f_flags |= O_NONBLOCK; + return 0; + + case SIOCGIFFLAGS: +#ifndef CONFIG_INET + case SIOCSIFFLAGS: +#endif + case SIOCGIFCONF: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCSIFLINK: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCSIFMAP: + case SIOCGIFMAP: + case SIOCSIFSLAVE: + case SIOCGIFSLAVE: + case SIOCGIFINDEX: + case SIOCGIFNAME: + case SIOCGIFCOUNT: + case SIOCSIFHWBROADCAST: + return(dev_ioctl(cmd,(void *) arg)); + +#ifdef CONFIG_INET + case SIOCADDRT: + case SIOCDELRT: + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + case SIOCDRARP: + case SIOCGRARP: + case SIOCSRARP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCSIFFLAGS: + case SIOCADDDLCI: + case SIOCDELDLCI: + return inet_dgram_ops.ioctl(sock, cmd, arg); +#endif + + default: + if ((cmd >= SIOCDEVPRIVATE) && + (cmd <= (SIOCDEVPRIVATE + 15))) + return(dev_ioctl(cmd,(void *) arg)); + +#ifdef CONFIG_NET_RADIO + if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) + return(dev_ioctl(cmd,(void *) arg)); +#endif + return -EOPNOTSUPP; + } + /*NOTREACHED*/ +} + +/*============================================================ + * wanpipe_debug + * + * This function will pass up information about all + * active sockets. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +static int wanpipe_debug (struct sock *origsk, void *arg) +{ + struct sock *sk=NULL; + netdevice_t *dev=NULL; + wanpipe_common_t *chan=NULL; + int cnt=0, err=0; + wan_debug_t *dbg_data = (wan_debug_t *)arg; + + for (sk = wanpipe_sklist; sk; sk = sk->next){ + + if (sk == origsk){ + continue; + } + + if ((err=put_user(1, &dbg_data->debug[cnt].free))) + return err; + if ((err=put_user(sk->state, &dbg_data->debug[cnt].sk_state))) + return err; + if ((err=put_user(sk->rcvbuf, &dbg_data->debug[cnt].rcvbuf))) + return err; + if ((err=put_user(atomic_read(&sk->rmem_alloc), &dbg_data->debug[cnt].rmem))) + return err; + if ((err=put_user(atomic_read(&sk->wmem_alloc), &dbg_data->debug[cnt].wmem))) + return err; + if ((err=put_user(sk->sndbuf, &dbg_data->debug[cnt].sndbuf))) + return err; + if ((err=put_user(sk_count, &dbg_data->debug[cnt].sk_count))) + return err; + if ((err=put_user(sk->protinfo.af_wanpipe->poll_cnt, + &dbg_data->debug[cnt].poll_cnt))) + return err; + if ((err=put_user(sk->bound_dev_if, &dbg_data->debug[cnt].bound))) + return err; + + if (sk->bound_dev_if){ + dev = dev_get_by_index(sk->bound_dev_if); + if (!dev) + continue; + + chan=dev->priv; + dev_put(dev); + + if ((err=put_user(chan->state, &dbg_data->debug[cnt].d_state))) + return err; + if ((err=put_user(chan->svc, &dbg_data->debug[cnt].svc))) + return err; + + if ((err=put_user(atomic_read(&chan->command), + &dbg_data->debug[cnt].command))) + return err; + + + if (sk->protinfo.af_wanpipe){ + sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card; + + if (card){ + if ((err=put_user(atomic_read(&card->u.x.command_busy), + &dbg_data->debug[cnt].cmd_busy))) + return err; + } + + if ((err=put_user(sk->protinfo.af_wanpipe->lcn, + &dbg_data->debug[cnt].lcn))) + return err; + + if (sk->protinfo.af_wanpipe->mbox){ + if ((err=put_user(1, &dbg_data->debug[cnt].mbox))) + return err; + } + } + + if ((err=put_user(atomic_read(&chan->receive_block), + &dbg_data->debug[cnt].rblock))) + return err; + + if (copy_to_user(dbg_data->debug[cnt].name, dev->name, strlen(dev->name))) + return -EFAULT; + } + + if (++cnt == MAX_NUM_DEBUG) + break; + } + return 0; +} + +/*============================================================ + * get_ioctl_cmd + * + * Pass up the contents of socket MBOX to the user. + *===========================================================*/ + +static int get_ioctl_cmd (struct sock *sk, void *arg) +{ + x25api_t *usr_data = (x25api_t *)arg; + mbox_cmd_t *mbox_ptr; + int err; + + if (usr_data == NULL) + return -EINVAL; + + if (!sk->protinfo.af_wanpipe->mbox){ + return -EINVAL; + } + + mbox_ptr = (mbox_cmd_t *)sk->protinfo.af_wanpipe->mbox; + + if ((err=put_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) + return err; + if ((err=put_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) + return err; + if ((err=put_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) + return err; + if ((err=put_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) + return err; + if ((err=put_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) + return err; + if ((err=put_user(mbox_ptr->cmd.lcn, &usr_data->hdr.lcn))) + return err; + + if (mbox_ptr->cmd.length > 0){ + if (mbox_ptr->cmd.length > X25_MAX_DATA) + return -EINVAL; + + if (copy_to_user(usr_data->data, mbox_ptr->data, mbox_ptr->cmd.length)){ + printk(KERN_INFO "wansock: Copy failed !!!\n"); + return -EFAULT; + } + } + return 0; +} + +/*============================================================ + * set_ioctl_cmd + * + * Before command can be execute, socket MBOX must + * be created, and initialized with user data. + *===========================================================*/ + +static int set_ioctl_cmd (struct sock *sk, void *arg) +{ + x25api_t *usr_data = (x25api_t *)arg; + mbox_cmd_t *mbox_ptr; + int err; + + if (!sk->protinfo.af_wanpipe->mbox){ + void *mbox_ptr; + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + if (!dev) + return -ENODEV; + + dev_put(dev); + + if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); + sk->protinfo.af_wanpipe->mbox = mbox_ptr; + + wanpipe_link_driver(dev,sk); + } + + mbox_ptr = (mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox; + memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); + + if (usr_data == NULL){ + return 0; + } + if ((err=get_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) + return err; + if ((err=get_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) + return err; + if ((err=get_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) + return err; + if ((err=get_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) + return err; + if ((err=get_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) + return err; + + if (mbox_ptr->cmd.length > 0){ + if (mbox_ptr->cmd.length > X25_MAX_DATA) + return -EINVAL; + + if (copy_from_user(mbox_ptr->data, usr_data->data, mbox_ptr->cmd.length)){ + printk(KERN_INFO "Copy failed\n"); + return -EFAULT; + } + } + return 0; +} + + +/*====================================================================== + * wanpipe_poll + * + * Datagram poll: Again totally generic. This also handles + * sequenced packet sockets providing the socket receive queue + * is only ever holding data ready to receive. + * + * Note: when you _don't_ use this routine for this protocol, + * and you use a different write policy from sock_writeable() + * then please supply your own write_space callback. + *=====================================================================*/ + +unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask; + + ++sk->protinfo.af_wanpipe->poll_cnt; + + poll_wait(file, sk->sleep, wait); + mask = 0; + + /* exceptional events? */ + if (sk->err || !skb_queue_empty(&sk->error_queue)){ + mask |= POLLPRI; + return mask; + } + if (sk->shutdown & RCV_SHUTDOWN) + mask |= POLLHUP; + + /* readable? */ + if (!skb_queue_empty(&sk->receive_queue)){ + mask |= POLLIN | POLLRDNORM; + } + + /* connection hasn't started yet */ + if (sk->state == WANSOCK_CONNECTING){ + return mask; + } + + if (sk->state == WANSOCK_DISCONNECTED){ + mask = POLLPRI; + return mask; + } + + /* This check blocks the user process if there is + * a packet already queued in the socket write queue. + * This option is only for X25API protocol, for other + * protocol like chdlc enable streaming mode, + * where multiple packets can be pending in the socket + * transmit queue */ + + if (sk->num == htons(X25_PROT)){ + if (atomic_read(&sk->protinfo.af_wanpipe->packet_sent)) + return mask; + } + + /* writable? */ + if (sock_writeable(sk)){ + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + }else{ + #ifdef LINUX_2_4 + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + #else + sk->socket->flags |= SO_NOSPACE; + #endif + } + + return mask; +} + +/*====================================================================== + * wanpipe_listen + * + * X25API Specific function. Set a socket into LISTENING MODE. + *=====================================================================*/ + + +static int wanpipe_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + if (sk->state == WANSOCK_BIND_LISTEN) { + + sk->max_ack_backlog = backlog; + sk->state = WANSOCK_LISTEN; + return 0; + }else{ + printk(KERN_INFO "wansock: Listening sock was not binded\n"); + } + + return -EINVAL; +} + +/*====================================================================== + * wanpipe_link_card + * + * Connects the listening socket to the driver + *=====================================================================*/ + +static int wanpipe_link_card (struct sock *sk) +{ + sdla_t *card; + + card = (sdla_t*)sk->protinfo.af_wanpipe->card; + if (!card) + return -ENOMEM; + + if ((card->sk != NULL) || (card->func != NULL)){ + printk(KERN_INFO "wansock: Listening queue is already established\n"); + return -EINVAL; + } + + card->sk=sk; + card->func=wanpipe_listen_rcv; + sk->zapped=1; + + return 0; +} + +/*====================================================================== + * wanpipe_listen + * + * X25API Specific function. Disconnect listening socket from + * the driver. + *=====================================================================*/ + +static void wanpipe_unlink_card (struct sock *sk) +{ + sdla_t *card; + + card = (sdla_t*)sk->protinfo.af_wanpipe->card; + + if (card){ + card->sk=NULL; + card->func=NULL; + } +} + +/*====================================================================== + * wanpipe_exec_cmd + * + * Ioctl function calls this function to execute user command. + * Connect() sytem call also calls this function to execute + * place call. This function blocks until command is executed. + *=====================================================================*/ + +static int wanpipe_exec_cmd(struct sock *sk, int cmd, unsigned int flags) +{ + int err = -EINVAL; + mbox_cmd_t *mbox_ptr = (mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox; + + if (!mbox_ptr){ + printk(KERN_INFO "NO MBOX PTR !!!!!\n"); + return -EINVAL; + } + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + + switch (cmd){ + + case SIOC_WANPIPE_ACCEPT_CALL: + + if (sk->state != WANSOCK_CONNECTING){ + err = -EHOSTDOWN; + break; + } + + err = execute_command(sk,X25_ACCEPT_CALL,0); + if (err < 0) + break; + + /* Update. Mar6 2000. + * Do not set the sock lcn number here, since + * it is done in wanpipe_listen_rcv(). + */ + if (sk->state == WANSOCK_CONNECTED){ + sk->protinfo.af_wanpipe->lcn = + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn; + DBG_PRINTK(KERN_INFO "\nwansock: Accept OK %i\n", + sk->protinfo.af_wanpipe->lcn ); + err = 0; + + }else{ + DBG_PRINTK (KERN_INFO "\nwansock: Accept Failed %i\n", + sk->protinfo.af_wanpipe->lcn); + sk->protinfo.af_wanpipe->lcn = 0; + err = -ECONNREFUSED; + } + break; + + case SIOC_WANPIPE_CLEAR_CALL: + + if (sk->state == WANSOCK_DISCONNECTED){ + err = -EINVAL; + break; + } + + + /* Check if data buffers are pending for transmission, + * if so, check wheter user wants to wait untill data + * is transmitted, or clear a call and drop packets */ + + if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){ + mbox_cmd_t *mbox = sk->protinfo.af_wanpipe->mbox; + if (mbox->cmd.qdm & 0x80){ + mbox->cmd.result = 0x35; + err = -EAGAIN; + break; + } + } + + sk->state = WANSOCK_DISCONNECTING; + + err = execute_command(sk,X25_CLEAR_CALL,0); + if (err < 0) + break; + + err = -ECONNREFUSED; + if (sk->state == WANSOCK_DISCONNECTED){ + DBG_PRINTK(KERN_INFO "\nwansock: CLEAR OK %i\n", + sk->protinfo.af_wanpipe->lcn); + sk->protinfo.af_wanpipe->lcn=0; + err = 0; + } + break; + + case SIOC_WANPIPE_RESET_CALL: + + if (sk->state != WANSOCK_CONNECTED){ + err = -EINVAL; + break; + } + + + /* Check if data buffers are pending for transmission, + * if so, check wheter user wants to wait untill data + * is transmitted, or reset a call and drop packets */ + + if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){ + mbox_cmd_t *mbox = sk->protinfo.af_wanpipe->mbox; + if (mbox->cmd.qdm & 0x80){ + mbox->cmd.result = 0x35; + err = -EAGAIN; + break; + } + } + + + err = execute_command(sk, X25_RESET,0); + if (err < 0) + break; + + err = mbox_ptr->cmd.result; + break; + + + case X25_PLACE_CALL: + + err=execute_command(sk,X25_PLACE_CALL,flags); + if (err < 0) + break; + + if (sk->state == WANSOCK_CONNECTED){ + + sk->protinfo.af_wanpipe->lcn = + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn; + + DBG_PRINTK(KERN_INFO "\nwansock: PLACE CALL OK %i\n", + sk->protinfo.af_wanpipe->lcn); + err = 0; + + }else if (sk->state == WANSOCK_CONNECTING && (flags & O_NONBLOCK)){ + sk->protinfo.af_wanpipe->lcn = + ((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn; + DBG_PRINTK(KERN_INFO "\nwansock: Place Call OK: Waiting %i\n", + sk->protinfo.af_wanpipe->lcn); + + err = 0; + + }else{ + DBG_PRINTK(KERN_INFO "\nwansock: Place call Failed\n"); + err = -ECONNREFUSED; + } + + break; + + default: + return -EINVAL; + } + + return err; +} + +static int check_driver_busy (struct sock *sk) +{ + netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); + wanpipe_common_t *chan; + + if (!dev) + return 0; + + dev_put(dev); + + if ((chan=dev->priv) == NULL) + return 0; + + return atomic_read(&chan->driver_busy); +} + + +/*====================================================================== + * wanpipe_accept + * + * ACCEPT() System call. X25API Specific function. + * For each incoming call, create a new socket and + * return it to the user. + *=====================================================================*/ + +static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct sock *sk; + struct sock *newsk; + struct sk_buff *skb; + DECLARE_WAITQUEUE(wait, current); + int err=0; + + if (newsock->sk != NULL){ + wanpipe_kill_sock_accept(newsock->sk); + newsock->sk=NULL; + } + + if ((sk = sock->sk) == NULL) + return -EINVAL; + + if (sk->type != SOCK_RAW) + return -EOPNOTSUPP; + + if (sk->state != WANSOCK_LISTEN) + return -EINVAL; + + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + add_wait_queue(sk->sleep,&wait); + current->state = TASK_INTERRUPTIBLE; + for (;;){ + skb = skb_dequeue(&sk->receive_queue); + if (skb){ + err=0; + break; + } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep,&wait); + + if (err != 0) + return err; + + newsk = get_newsk_from_skb(skb); + if (!newsk){ + return -EINVAL; + } + + set_bit(1,&wanpipe_tx_critical); + write_lock(&wanpipe_sklist_lock); + newsk->next = wanpipe_sklist; + wanpipe_sklist = newsk; + sock_hold(sk); + write_unlock(&wanpipe_sklist_lock); + clear_bit(1,&wanpipe_tx_critical); + + newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; + + /* Now attach up the new socket */ + sk->ack_backlog--; + newsock->sk = newsk; + + kfree_skb(skb); + + DBG_PRINTK(KERN_INFO "\nwansock: ACCEPT Got LCN %i\n",newsk->protinfo.af_wanpipe->lcn); + return 0; +} + +/*====================================================================== + * get_newsk_from_skb + * + * Accept() uses this function to get the address of the new + * socket structure. + *=====================================================================*/ + +struct sock * get_newsk_from_skb (struct sk_buff *skb) +{ + netdevice_t *dev = skb->dev; + wanpipe_common_t *chan; + + if (!dev){ + return NULL; + } + + if ((chan = dev->priv) == NULL){ + return NULL; + } + + if (!chan->sk){ + return NULL; + } + return (struct sock *)chan->sk; +} + +/*====================================================================== + * wanpipe_connect + * + * CONNECT() System Call. X25API specific function + * Check the state of the sock, and execute PLACE_CALL command. + * Connect can ether block or return without waiting for connection, + * if specified by user. + *=====================================================================*/ + +static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +{ + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr; + netdevice_t *dev; + int err; + + if (sk->num != htons(X25_PROT)) + return -EINVAL; + + if (sk->state == WANSOCK_CONNECTED) + return EISCONN; /* No reconnect on a seqpacket socket */ + + if (sk->state != WAN_DISCONNECTED){ + printk(KERN_INFO "wansock: Trying to connect on channel NON DISCONNECT\n"); + return -ECONNREFUSED; + } + + sk->state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; + + if (addr_len != sizeof(struct wan_sockaddr_ll)) + return -EINVAL; + + if (addr->sll_family != AF_WANPIPE) + return -EINVAL; + + if ((dev = dev_get_by_index(sk->bound_dev_if)) == NULL) + return -ENETUNREACH; + + dev_put(dev); + + if (!sk->zapped) /* Must bind first - autobinding does not work */ + return -EINVAL; + + sock->state = SS_CONNECTING; + sk->state = WANSOCK_CONNECTING; + + if (!sk->protinfo.af_wanpipe->mbox){ + if (sk->protinfo.af_wanpipe->svc){ + return -EINVAL; + }else{ + int err; + if ((err=set_ioctl_cmd(sk,NULL)) < 0) + return err; + } + } + + if ((err=wanpipe_exec_cmd(sk, X25_PLACE_CALL,flags)) != 0){ + sock->state = SS_UNCONNECTED; + sk->state = WANSOCK_CONNECTED; + return err; + } + + if (sk->state != WANSOCK_CONNECTED && (flags & O_NONBLOCK)){ + return 0; + } + + if (sk->state != WANSOCK_CONNECTED) { + sock->state = SS_UNCONNECTED; + return -ECONNREFUSED; + } + + sock->state = SS_CONNECTED; + return 0; +} + +#ifdef LINUX_2_4 +struct proto_ops wanpipe_ops = { + family: PF_WANPIPE, + + release: wanpipe_release, + bind: wanpipe_bind, + connect: wanpipe_connect, + socketpair: sock_no_socketpair, + accept: wanpipe_accept, + getname: wanpipe_getname, + poll: wanpipe_poll, + ioctl: wanpipe_ioctl, + listen: wanpipe_listen, + shutdown: sock_no_shutdown, + setsockopt: sock_no_setsockopt, + getsockopt: sock_no_getsockopt, + sendmsg: wanpipe_sendmsg, + recvmsg: wanpipe_recvmsg +}; +#else +struct proto_ops wanpipe_ops = { + PF_WANPIPE, + + sock_no_dup, + wanpipe_release, + wanpipe_bind, + wanpipe_connect, + sock_no_socketpair, + wanpipe_accept, + wanpipe_getname, + wanpipe_poll, + wanpipe_ioctl, + wanpipe_listen, + sock_no_shutdown, + sock_no_setsockopt, + sock_no_getsockopt, + sock_no_fcntl, + wanpipe_sendmsg, + wanpipe_recvmsg +}; +#endif + + +static struct net_proto_family wanpipe_family_ops = { + PF_WANPIPE, + wanpipe_create +}; + +struct notifier_block wanpipe_netdev_notifier={ + wanpipe_notifier, + NULL, + 0 +}; + + +#ifdef MODULE +void cleanup_module(void) +{ + printk(KERN_INFO "wansock: Cleaning up \n"); + unregister_netdevice_notifier(&wanpipe_netdev_notifier); + sock_unregister(PF_WANPIPE); + return; +} + + +int init_module(void) +{ + + printk(KERN_INFO "wansock: Registering Socket \n"); + sock_register(&wanpipe_family_ops); + register_netdevice_notifier(&wanpipe_netdev_notifier); + return 0; +} +#endif diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/patchlevel linux/net/wanrouter/patchlevel --- v2.4.3/linux/net/wanrouter/patchlevel Thu Jan 7 09:25:02 1999 +++ linux/net/wanrouter/patchlevel Thu Apr 12 12:11:39 2001 @@ -1 +1 @@ -2.0.3 +2.2.1 diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c --- v2.4.3/linux/net/wanrouter/wanmain.c Sun Mar 25 18:14:25 2001 +++ linux/net/wanrouter/wanmain.c Thu Apr 12 12:11:39 2001 @@ -18,6 +18,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels +* Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and +* greater. +* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on +* kernels 2.2.16 or greater. The SyncPPP +* has changed. +* Jul 13, 2000 Nenad Corbic Added SyncPPP support +* Added extra debugging in device_setup(). * Oct 01, 1999 Gideon Hack Update for s514 PCI card * Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) * Jan 16, 1997 Gene Kozin router_devlist made public @@ -31,7 +39,6 @@ * Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate * kernel memory and copy configuration data to * kernel space (for big firmwares) -* May 19, 1999 Arnaldo Melo __init in wanrouter_init * Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. *****************************************************************************/ @@ -41,17 +48,95 @@ #include <linux/errno.h> /* return codes */ #include <linux/kernel.h> #include <linux/module.h> /* support for loadable modules */ -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/mm.h> /* verify_area(), etc. */ #include <linux/string.h> /* inline mem*, str* functions */ -#include <linux/vmalloc.h> /* vmalloc, vfree */ -#include <asm/segment.h> /* kernel <-> user copy */ + #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> /* copy_to/from_user */ #include <linux/wanrouter.h> /* WAN router API definitions */ -#include <linux/init.h> /* __init et al. */ +#if defined(LINUX_2_4) + #include <linux/vmalloc.h> /* vmalloc, vfree */ + #include <asm/uaccess.h> /* copy_to/from_user */ + #include <linux/init.h> /* __initfunc et al. */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + #include <net/syncppp.h> +#else + #include <../drivers/net/wan/syncppp.h> +#endif + +#elif defined(LINUX_2_1) + #define LINUX_2_1 + #include <linux/vmalloc.h> /* vmalloc, vfree */ + #include <asm/uaccess.h> /* copy_to/from_user */ + #include <linux/init.h> /* __initfunc et al. */ + #include <../drivers/net/syncppp.h> + +#else + #include <asm/segment.h> /* kernel <-> user copy */ +#endif + +#define KMEM_SAFETYZONE 8 + +/***********FOR DEBUGGING PURPOSES********************************************* +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +*****************************************************************************/ + /* * Defines and Macros @@ -91,14 +176,18 @@ */ static wan_device_t *find_device (char *name); -static int delete_interface (wan_device_t *wandev, char *name, int force); +static int delete_interface (wan_device_t *wandev, char *name); +void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); + + /* * Global Data */ -static char fullname[] = "WAN Router"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; +static char fullname[] = "Sangoma WANPIPE Router"; +static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; static char modname[] = ROUTER_NAME; /* short module name */ wan_device_t* router_devlist = NULL; /* list of registered devices */ static int devcnt = 0; @@ -113,31 +202,41 @@ #endif #ifndef MODULE -int __init wanrouter_init(void) + +int wanrouter_init(void) { int err; - extern int wanpipe_init(void), - cyclomx_init(void); + extern int wanpipe_init(void); + extern int sdladrv_init(void); printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); + err = wanrouter_proc_init(); - if (err) - printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname); + if (err){ + printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); + } + + /* + * Initialise compiled in boards + */ - /* - * Initialise compiled in boards - */ - #ifdef CONFIG_VENDOR_SANGOMA + sdladrv_init(); wanpipe_init(); #endif -#ifdef CONFIG_CYCLADES_SYNC - cyclomx_init(); -#endif + return err; } + +#ifdef LINUX_2_4 +static void __exit wanrouter_cleanup (void) +{ + wanrouter_proc_cleanup(); +} +#endif + #else /* @@ -161,9 +260,13 @@ printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); + err = wanrouter_proc_init(); - if (err) printk(KERN_ERR + + if (err){ + printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); + } return err; } @@ -207,7 +310,7 @@ if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || (wandev->name == NULL)) return -EINVAL; - + namelen = strlen(wandev->name); if (!namelen || (namelen > WAN_DRVNAME_SZ)) return -EINVAL; @@ -219,12 +322,13 @@ printk(KERN_INFO "%s: registering WAN device %s\n", modname, wandev->name); #endif + /* * Register /proc directory entry */ err = wanrouter_proc_add(wandev); if (err) { - printk(KERN_ERR + printk(KERN_INFO "%s: can't create /proc/net/router/%s entry!\n", modname, wandev->name); return err; @@ -274,17 +378,17 @@ #ifdef WANDEBUG printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name); #endif - + if (wandev->state != WAN_UNCONFIGURED) { - while(wandev->dev) - delete_interface(wandev, wandev->dev->name, 1); - if (wandev->shutdown) - wandev->shutdown(wandev); + device_shutdown(wandev); } - if (prev) + + if (prev){ prev->next = wandev->next; - else + }else{ router_devlist = wandev->next; + } + --devcnt; wanrouter_proc_delete(wandev); MOD_DEC_USE_COUNT; @@ -302,12 +406,12 @@ */ -int wanrouter_encapsulate (struct sk_buff* skb, struct net_device* dev) +int wanrouter_encapsulate (struct sk_buff *skb, netdevice_t *dev, + unsigned short type) { int hdr_len = 0; - switch (skb->protocol) - { + switch (type) { case ETH_P_IP: /* IP datagram encapsulation */ hdr_len += 1; skb_push(skb, 1); @@ -321,18 +425,19 @@ skb->data[0] = 0; skb->data[1] = NLPID_SNAP; memcpy(&skb->data[2], oui_ether, sizeof(oui_ether)); - *((unsigned short*)&skb->data[5]) = htons(skb->protocol); + *((unsigned short*)&skb->data[5]) = htons(type); break; default: /* Unknown packet type */ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - modname, skb->protocol, dev->name); + modname, type, dev->name); hdr_len = -EINVAL; } return hdr_len; } + /* * Decapsulate packet. * @@ -344,21 +449,19 @@ */ -unsigned short wanrouter_type_trans (struct sk_buff* skb, struct net_device* dev) +unsigned short wanrouter_type_trans (struct sk_buff *skb, netdevice_t *dev) { int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ unsigned short ethertype; - switch (skb->data[cnt]) - { + switch (skb->data[cnt]) { case NLPID_IP: /* IP datagramm */ ethertype = htons(ETH_P_IP); cnt += 1; break; case NLPID_SNAP: /* SNAP encapsulation */ - if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))) - { + if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))){ printk(KERN_INFO "%s: unsupported SNAP OUI %02X-%02X-%02X " "on interface %s!\n", modname, @@ -380,8 +483,8 @@ } skb->protocol = ethertype; skb->pkt_type = PACKET_HOST; /* Physically point to point */ - skb->mac.raw = skb->data; skb_pull(skb, cnt); + skb->mac.raw = skb->data; return ethertype; } @@ -399,9 +502,11 @@ struct proc_dir_entry *dent; wan_device_t *wandev; + #if defined (LINUX_2_1) || defined (LINUX_2_4) if (!capable(CAP_NET_ADMIN)){ return -EPERM; } + #endif if ((cmd >> 8) != ROUTER_IOCTL) return -EINVAL; @@ -466,44 +571,105 @@ wandev_conf_t *conf; int err = -EINVAL; - if (wandev->setup == NULL) /* Nothing to do ? */ + if (wandev->setup == NULL){ /* Nothing to do ? */ + printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n", + wandev->name); return 0; + } + + #ifdef LINUX_2_0 + err = verify_area (VERIFY_READ, u_conf, sizeof(wandev_conf_t)); + if(err){ + return err; + } + #endif conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); - if (conf == NULL) + if (conf == NULL){ + printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", + wandev->name); return -ENOBUFS; - + } + + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { + printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", + wandev->name); kfree(conf); return -EFAULT; } + #else + memcpy_fromfs ((void *)conf, (void *)u_conf, sizeof(wandev_conf_t)); + #endif - if (conf->magic != ROUTER_MAGIC) { + if (conf->magic != ROUTER_MAGIC){ kfree(conf); + printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n", + wandev->name); return -EINVAL; } - if (conf->data_size && conf->data) { + if (conf->data_size && conf->data){ if(conf->data_size > 128000 || conf->data_size < 0) { kfree(conf); + printk(KERN_INFO + "%s: ERROR, Invalid firmware data size %i !\n", + wandev->name, conf->data_size); return -EINVAL;; } +#if defined (LINUX_2_1) || defined (LINUX_2_4) data = vmalloc(conf->data_size); if (data) { if(!copy_from_user(data, conf->data, conf->data_size)){ conf->data=data; err = wandev->setup(wandev,conf); - } - else + }else{ + printk(KERN_INFO + "%s: ERROR, Faild to copy from user data !\n", + wandev->name); err = -EFAULT; - } - else + } + }else{ + printk(KERN_INFO + "%s: ERROR, Faild allocate kernel memory !\n", + wandev->name); err = -ENOBUFS; - - if (data) + } + + if (data){ vfree(data); + } +#else + err = verify_area(VERIFY_READ, conf->data, conf->data_size); + if (!err) { + data = kmalloc(conf->data_size, GFP_KERNEL); + if (data) { + memcpy_fromfs(data, (void*)conf->data, + conf->data_size); + conf->data = data; + }else{ + printk(KERN_INFO + "%s: ERROR, Faild allocate kernel memory !\n",wandev->name); + err = -ENOMEM; + } + }else{ + printk(KERN_INFO + "%s: ERROR, Faild to copy from user data !\n",wandev->name); + } + if (!err){ + err = wandev->setup(wandev, conf); + } + + if (data){ + kfree(data); + } +#endif + }else{ + printk(KERN_INFO + "%s: ERROR, No firmware found ! Firmware size = %i !\n", + wandev->name, conf->data_size); } kfree(conf); @@ -516,27 +682,37 @@ * o call driver's shutdown() entry point */ -static int device_shutdown (wan_device_t* wandev) +static int device_shutdown (wan_device_t *wandev) { - struct net_device* dev; - - if (wandev->state == WAN_UNCONFIGURED) + netdevice_t *dev; + int err=0; + + if (wandev->state == WAN_UNCONFIGURED){ return 0; + } + + printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name); - for (dev = wandev->dev; dev;) - { - if (delete_interface(wandev, dev->name, 0)) - { - struct net_device **slave = dev->priv; - dev = *slave; + for (dev = wandev->dev; dev;) { + if ((err=delete_interface(wandev, dev->name)) != 0){ + return err; } + + /* The above function deallocates the current dev + * structure. Therefore, we cannot use dev->priv + * as the next element: wandev->dev points to the + * next element */ + dev = wandev->dev; } - if (wandev->ndev) + + if (wandev->ndev){ return -EBUSY; /* there are opened interfaces */ - + } + if (wandev->shutdown) - return wandev->shutdown(wandev); - return 0; + err=wandev->shutdown(wandev); + + return err; } /* @@ -547,6 +723,13 @@ { wandev_stat_t stat; + #ifdef LINUX_2_0 + int err; + err = verify_area(VERIFY_WRITE, u_stat, sizeof(wandev_stat_t)); + if (err) + return err; + #endif + memset(&stat, 0, sizeof(stat)); /* Ask device driver to update device statistics */ @@ -557,8 +740,12 @@ stat.ndev = wandev->ndev; stat.state = wandev->state; + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_to_user(u_stat, &stat, sizeof(stat))) return -EFAULT; + #else + memcpy_tofs((void*)u_stat, (void*)&stat, sizeof(stat)); + #endif return 0; } @@ -573,58 +760,149 @@ * o register network interface */ -static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf) +static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf) { wanif_conf_t conf; - struct net_device *dev; + netdevice_t *dev=NULL; + #ifdef CONFIG_WANPIPE_MULTPPP + struct ppp_device *pppdev=NULL; + #endif int err; if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) return -ENODEV; - + + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t))) return -EFAULT; + #else + err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t)); + if (err) + return err; + memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t)); + #endif if (conf.magic != ROUTER_MAGIC) return -EINVAL; + + err = -EPROTONOSUPPORT; + + +#ifdef CONFIG_WANPIPE_MULTPPP + if (conf.config_id == WANCONFIG_MPPP){ + + pppdev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); + if (pppdev == NULL){ + return -ENOBUFS; + } + memset(pppdev, 0, sizeof(struct ppp_device)); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) + pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); + if (pppdev->dev == NULL){ + return -ENOBUFS; + } + memset(pppdev->dev, 0, sizeof(netdevice_t)); + #endif - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == NULL) - return -ENOBUFS; + err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf); - memset(dev, 0, sizeof(struct net_device)); - err = wandev->new_if(wandev, dev, &conf); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16) + dev = pppdev->dev; + #else + dev = &pppdev->dev; + #endif + + }else{ + + dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); + if (dev == NULL){ + return -ENOBUFS; + } + memset(dev, 0, sizeof(netdevice_t)); + err = wandev->new_if(wandev, dev, &conf); + } + +#else + /* Sync PPP is disabled */ + if (conf.config_id != WANCONFIG_MPPP){ + + dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL); + if (dev == NULL){ + return -ENOBUFS; + } + memset(dev, 0, sizeof(netdevice_t)); + err = wandev->new_if(wandev, dev, &conf); + }else{ + printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", + wandev->name); + return err; + } +#endif + if (!err) { /* Register network interface. This will invoke init() * function supplied by the driver. If device registered * successfully, add it to the interface list. */ - if (dev->name == NULL) + + if (dev->name == NULL){ err = -EINVAL; - - else if (dev_get(dev->name)) + }else if (dev_get(dev->name)){ err = -EEXIST; /* name already exists */ - else { -#ifdef WANDEBUG + }else{ + + #ifdef WANDEBUG printk(KERN_INFO "%s: registering interface %s...\n", modname, dev->name); -#endif + #endif + err = register_netdev(dev); if (!err) { - struct net_device **slave = dev->priv; + netdevice_t *slave=NULL; + unsigned long smp_flags=0; + + lock_adapter_irq(&wandev->lock, &smp_flags); + + if (wandev->dev == NULL){ + wandev->dev = dev; + }else{ + for (slave=wandev->dev; + *((netdevice_t**)slave->priv); + slave=*((netdevice_t**)slave->priv)); - cli(); /***** critical section start *****/ - *slave = wandev->dev; - wandev->dev = dev; + *((netdevice_t**)slave->priv) = dev; + } ++wandev->ndev; - sti(); /****** critical section end ******/ + + unlock_adapter_irq(&wandev->lock, &smp_flags); return 0; /* done !!! */ } } if (wandev->del_if) wandev->del_if(wandev, dev); } - kfree(dev); + + /* This code has moved from del_if() function */ + if (dev->priv){ + kfree(dev->priv); + dev->priv=NULL; + } + + + #ifdef CONFIG_WANPIPE_MULTPPP + if (conf.config_id == WANCONFIG_MPPP){ + kfree(pppdev); + }else{ + kfree(dev); + } + #else + /* Sync PPP is disabled */ + if (conf.config_id != WANCONFIG_MPPP){ + kfree(dev); + } + #endif + return err; } @@ -638,15 +916,43 @@ static int device_del_if (wan_device_t *wandev, char *u_name) { char name[WAN_IFNAME_SZ + 1]; + int err = 0; if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; + #ifdef LINUX_2_0 + err = verify_area(VERIFY_READ, u_name, WAN_IFNAME_SZ); + if (err) + return err; + #endif + memset(name, 0, sizeof(name)); + #if defined (LINUX_2_1) || defined (LINUX_2_4) if(copy_from_user(name, u_name, WAN_IFNAME_SZ)) return -EFAULT; - return delete_interface(wandev, name, 0); + #else + memcpy_fromfs((void*)name, (void*)u_name, WAN_IFNAME_SZ); + #endif + + err = delete_interface(wandev, name); + if (err) + return(err); + + /* If last interface being deleted, shutdown card + * This helps with administration at leaf nodes + * (You can tell if the person at the other end of the phone + * has an interface configured) and avoids DoS vulnerabilities + * in binary driver files - this fixes a problem with the current + * Sangoma driver going into strange states when all the network + * interfaces are deleted and the link irrecoverably disconnected. + */ + + if (!wandev->ndev && wandev->shutdown){ + err = wandev->shutdown(wandev); + } + return err; } @@ -685,59 +991,102 @@ * sure that opened interfaces are not removed! */ -static int delete_interface (wan_device_t *wandev, char *name, int force) +static int delete_interface (wan_device_t *wandev, char *name) { - struct net_device *dev, *prev; + netdevice_t *dev=NULL, *prev=NULL; + unsigned long smp_flags=0; + lock_adapter_irq(&wandev->lock, &smp_flags); dev = wandev->dev; prev = NULL; while (dev && strcmp(name, dev->name)) { - struct net_device **slave = dev->priv; - + netdevice_t **slave = dev->priv; prev = dev; dev = *slave; } - - if (dev == NULL) + unlock_adapter_irq(&wandev->lock, &smp_flags); + + if (dev == NULL){ return -ENODEV; /* interface not found */ - - if (netif_running(dev)) { - if (force) { - printk(KERN_WARNING - "%s: deleting opened interface %s!\n", - modname, name); - } - else - return -EBUSY; /* interface in use */ + } + + #ifdef LINUX_2_4 + if (netif_running(dev)){ + #else + if (dev->start) { + #endif + return -EBUSY; /* interface in use */ } if (wandev->del_if) wandev->del_if(wandev, dev); - cli(); /***** critical section start *****/ + lock_adapter_irq(&wandev->lock, &smp_flags); if (prev) { - struct net_device **prev_slave = prev->priv; - struct net_device **slave = dev->priv; + netdevice_t **prev_slave = prev->priv; + netdevice_t **slave = dev->priv; *prev_slave = *slave; } else { - struct net_device **slave = dev->priv; - + netdevice_t **slave = dev->priv; wandev->dev = *slave; } --wandev->ndev; - sti(); /****** critical section end ******/ + unlock_adapter_irq(&wandev->lock, &smp_flags); + + printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); + + /* Due to new interface linking method using dev->priv, + * this code has moved from del_if() function.*/ + if (dev->priv){ + kfree(dev->priv); + dev->priv=NULL; + } - printk("Unregistering '%s'\n", dev->name); unregister_netdev(dev); + + #ifdef LINUX_2_4 + kfree(dev); + #else + if (dev->name){ + kfree(dev->name); + } kfree(dev); + #endif + return 0; } +void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +{ + #ifdef LINUX_2_0 + save_flags(*smp_flags); + cli(); + #else + spin_lock_irqsave(lock, *smp_flags); + #endif +} + + +void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +{ + #ifdef LINUX_2_0 + restore_flags(*smp_flags); + #else + spin_unlock_irqrestore(lock, *smp_flags); + #endif +} + + + +#if defined (LINUX_2_1) || defined (LINUX_2_4) EXPORT_SYMBOL(register_wan_device); EXPORT_SYMBOL(unregister_wan_device); EXPORT_SYMBOL(wanrouter_encapsulate); EXPORT_SYMBOL(wanrouter_type_trans); +EXPORT_SYMBOL(lock_adapter_irq); +EXPORT_SYMBOL(unlock_adapter_irq); +#endif /* * End diff -u --recursive --new-file v2.4.3/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c --- v2.4.3/linux/net/wanrouter/wanproc.c Fri Feb 9 11:34:13 2001 +++ linux/net/wanrouter/wanproc.c Thu Apr 12 12:11:39 2001 @@ -13,7 +13,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Jan 20, 2001 Arnaldo C.Melo Fix leak on error in router_proc_read, cleanups * Jun 02, 1999 Gideon Hack Updates for Linux 2.2.X kernels. * Jun 29, 1997 Alan Cox Merged with 1.0.3 vendor code * Jan 29, 1997 Gene Kozin v1.0.1. Implemented /proc read routines @@ -26,397 +25,1017 @@ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ #include <linux/kernel.h> -#include <linux/slab.h> /* kmalloc(), kfree() */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/mm.h> /* verify_area(), etc. */ #include <linux/string.h> /* inline mem*, str* functions */ -#include <linux/init.h> /* __init et al. */ -#include <asm/segment.h> /* kernel <-> user copy */ #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> /* copy_to_user */ #include <asm/io.h> #include <linux/wanrouter.h> /* WAN router API definitions */ -/****** Defines and Macros **************************************************/ -#define PROC_STATS_FORMAT "%30s: %12lu\n" +#if defined(LINUX_2_1) || defined(LINUX_2_4) + #include <linux/init.h> /* __initfunc et al. */ + #include <asm/uaccess.h> /* copy_to_user */ + #define PROC_STATS_FORMAT "%30s: %12lu\n" +#else + #define PROC_STATS_FORMAT "%30s: %12u\n" + #include <asm/segment.h> /* kernel <-> user copy */ +#endif + + +/****** Defines and Macros **************************************************/ #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif #define PROC_BUFSZ 4000 /* buffer size for printing proc info */ +#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\ + (prot == WANCONFIG_X25) ? " X25" : \ + (prot == WANCONFIG_PPP) ? " PPP" : \ + (prot == WANCONFIG_CHDLC) ? " CHDLC": \ + (prot == WANCONFIG_MPPP) ? " MPPP" : \ + " Unknown" ) + +/****** Data Types **********************************************************/ + +typedef struct wan_stat_entry +{ + struct wan_stat_entry *next; + char *description; /* description string */ + void *data; /* -> data */ + unsigned data_type; /* data type */ +} wan_stat_entry_t; + /****** Function Prototypes *************************************************/ #ifdef CONFIG_PROC_FS -/* Proc filesystem interface */ -static int router_proc_perms(struct inode *, int); -static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); -/* Methods for preparing data for reading proc entries */ +#ifdef LINUX_2_4 /* Start of LINUX 2.4.X code */ -static int config_get_info(char* buf, char** start, off_t offs, int len); -static int status_get_info(char* buf, char** start, off_t offs, int len); -static int wandev_get_info(char* buf, char** start, off_t offs, int len); -/* Miscellaneous */ + /* Proc filesystem interface */ + static int router_proc_perms(struct inode *, int); + static ssize_t router_proc_read(struct file* file, char* buf, size_t count, loff_t *ppos); + + /* Methods for preparing data for reading proc entries */ + + static int config_get_info(char* buf, char** start, off_t offs, int len); + static int status_get_info(char* buf, char** start, off_t offs, int len); + static int wandev_get_info(char* buf, char** start, off_t offs, int len); + + /* Miscellaneous */ + + /* + * Structures for interfacing with the /proc filesystem. + * Router creates its own directory /proc/net/router with the folowing + * entries: + * config device configuration + * status global device statistics + * <device> entry for each WAN device + */ + + /* + * Generic /proc/net/router/<file> file and inode operations + */ + static struct file_operations router_fops = + { + read: router_proc_read, + }; + + static struct inode_operations router_inode = + { + permission: router_proc_perms, + }; + + /* + * /proc/net/router/<device> file operations + */ + + static struct file_operations wandev_fops = + { + read: router_proc_read, + ioctl: wanrouter_ioctl, + }; + + /* + * /proc/net/router + */ + + static struct proc_dir_entry *proc_router; + + /* Strings */ + static char conf_hdr[] = + "Device name | port |IRQ|DMA| mem.addr |mem.size|" + "option1|option2|option3|option4\n"; + + static char stat_hdr[] = + "Device name |protocol|station|interface|clocking|baud rate" + "| MTU |ndev|link state\n"; + + + /* + * Interface functions + */ + + /* + * Initialize router proc interface. + */ + + int __init wanrouter_proc_init (void) + { + struct proc_dir_entry *p; + proc_router = proc_mkdir(ROUTER_NAME, proc_net); + if (!proc_router) + goto fail; + + p = create_proc_entry("config",0,proc_router); + if (!p) + goto fail_config; + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = config_get_info; + p = create_proc_entry("status",0,proc_router); + if (!p) + goto fail_stat; + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = status_get_info; + return 0; + fail_stat: + remove_proc_entry("config", proc_router); + fail_config: + remove_proc_entry(ROUTER_NAME, proc_net); + fail: + return -ENOMEM; + } -/* - * Structures for interfacing with the /proc filesystem. - * Router creates its own directory /proc/net/wanrouter with the folowing - * entries: - * config device configuration - * status global device statistics - * <device> entry for each WAN device - */ + /* + * Clean up router proc interface. + */ + + void wanrouter_proc_cleanup (void) + { + remove_proc_entry("config", proc_router); + remove_proc_entry("status", proc_router); + remove_proc_entry(ROUTER_NAME,proc_net); + } -/* - * Generic /proc/net/wanrouter/<file> file and inode operations - */ -static struct file_operations router_fops = -{ - read: router_proc_read, -}; + /* + * Add directory entry for WAN device. + */ + + int wanrouter_proc_add (wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + wandev->dent = create_proc_entry(wandev->name, 0, proc_router); + if (!wandev->dent) + return -ENOMEM; + wandev->dent->proc_fops = &wandev_fops; + wandev->dent->proc_iops = &router_inode; + wandev->dent->get_info = wandev_get_info; + wandev->dent->data = wandev; + return 0; + } -static struct inode_operations router_inode = -{ - permission: router_proc_perms, -}; + /* + * Delete directory entry for WAN device. + */ + + int wanrouter_proc_delete(wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + remove_proc_entry(wandev->name, proc_router); + return 0; + } -/* - * /proc/net/wanrouter/<device> file operations - */ + /****** Proc filesystem entry points ****************************************/ -static struct file_operations wandev_fops = -{ - read: router_proc_read, - ioctl: wanrouter_ioctl, -}; + /* + * Verify access rights. + */ -/* - * /proc/net/wanrouter - */ + static int router_proc_perms (struct inode* inode, int op) + { + return 0; + } -static struct proc_dir_entry *proc_router; + /* + * Read router proc directory entry. + * This is universal routine for reading all entries in /proc/net/wanrouter + * directory. Each directory entry contains a pointer to the 'method' for + * preparing data for that entry. + * o verify arguments + * o allocate kernel buffer + * o call get_info() to prepare data + * o copy data to user space + * o release kernel buffer + * + * Return: number of bytes copied to user space (0, if no data) + * <0 error + */ + + static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) + { + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int pos, offs, len; + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return 0; + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + + pos = dent->get_info(page, dent->data, 0, 0); + offs = file->f_pos; + if (offs < pos) { + len = min(pos - offs, count); + if(copy_to_user(buf, (page + offs), len)) + return -EFAULT; + file->f_pos += len; + } + else + len = 0; + kfree(page); + return len; + } -/* Strings */ -static char conf_hdr[] = - "Device name | port |IRQ|DMA| mem.addr |mem.size|" - "option1|option2|option3|option4\n"; - -static char stat_hdr[] = - "Device name |station|interface|clocking|baud rate| MTU |ndev" - "|link state\n"; + /* + * Prepare data for reading 'Config' entry. + * Return length of data. + */ + + static int config_get_info(char* buf, char** start, off_t offs, int len) + { + int cnt = sizeof(conf_hdr) - 1; + wan_device_t* wandev; + strcpy(buf, conf_hdr); + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 120)); + wandev = wandev->next) { + if (wandev->state) cnt += sprintf(&buf[cnt], + "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", + wandev->name, + wandev->ioport, + wandev->irq, + wandev->dma, + wandev->maddr, + wandev->msize, + wandev->hw_opt[0], + wandev->hw_opt[1], + wandev->hw_opt[2], + wandev->hw_opt[3]); + } + return cnt; + } -/* - * Interface functions - */ + /* + * Prepare data for reading 'Status' entry. + * Return length of data. + */ + + static int status_get_info(char* buf, char** start, off_t offs, int len) + { + int cnt = 0; + wan_device_t* wandev; + + //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n"); + strcpy(&buf[cnt], stat_hdr); + cnt += sizeof(stat_hdr) - 1; + + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 80)); + wandev = wandev->next) { + if (!wandev->state) continue; + cnt += sprintf(&buf[cnt], + "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", + wandev->name, + PROT_DECODE(wandev->config_id), + wandev->config_id == WANCONFIG_FR ? + (wandev->station ? " Node" : " CPE") : + (wandev->config_id == WANCONFIG_X25 ? + (wandev->station ? " DCE" : " DTE") : + (" N/A")), + wandev->interface ? " V.35" : " RS-232", + wandev->clocking ? "internal" : "external", + wandev->bps, + wandev->mtu, + wandev->ndev); + + switch (wandev->state) { + + case WAN_UNCONFIGURED: + cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); + break; + + case WAN_DISCONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); + break; + + case WAN_CONNECTING: + cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); + break; + + case WAN_CONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); + break; -/* - * Initialize router proc interface. - */ + default: + cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); + break; + } + } + return cnt; + } -int __init wanrouter_proc_init (void) -{ - struct proc_dir_entry *p; - proc_router = proc_mkdir(ROUTER_NAME, proc_net); - if (!proc_router) - goto fail; - - p = create_proc_entry("config",0,proc_router); - if (!p) - goto fail_config; - p->proc_fops = &router_fops; - p->proc_iops = &router_inode; - p->get_info = config_get_info; - p = create_proc_entry("status",0,proc_router); - if (!p) - goto fail_stat; - p->proc_fops = &router_fops; - p->proc_iops = &router_inode; - p->get_info = status_get_info; - return 0; -fail_stat: - remove_proc_entry("config", proc_router); -fail_config: - remove_proc_entry(ROUTER_NAME, proc_net); -fail: - return -ENOMEM; -} + /* + * Prepare data for reading <device> entry. + * Return length of data. + * + * On entry, the 'start' argument will contain a pointer to WAN device + * data space. + */ + + static int wandev_get_info(char* buf, char** start, off_t offs, int len) + { + wan_device_t* wandev = (void*)start; + int cnt = 0; + int rslt = 0; + + if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) + return 0; + if (!wandev->state) + return sprintf(&buf[cnt], "device is not configured!\n"); + + /* Update device statistics */ + if (wandev->update) { + + rslt = wandev->update(wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + return sprintf(&buf[cnt], "Device is busy!\n"); + + default: + return sprintf(&buf[cnt], + "Device is not configured!\n"); + } + } + } -/* - * Clean up router proc interface. - */ + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets received", wandev->stats.rx_packets); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets transmitted", wandev->stats.tx_packets); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes received", wandev->stats.rx_bytes); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes transmitted", wandev->stats.tx_bytes); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "bad packets received", wandev->stats.rx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "packet transmit problems", wandev->stats.tx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "received frames dropped", wandev->stats.rx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit frames dropped", wandev->stats.tx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "multicast packets received", wandev->stats.multicast); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit collisions", wandev->stats.collisions); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receive length errors", wandev->stats.rx_length_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver overrun errors", wandev->stats.rx_over_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "frame format errors (aborts)", wandev->stats.rx_frame_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver fifo overrun", wandev->stats.rx_fifo_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver missed packet", wandev->stats.rx_missed_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "aborted frames transmitted", wandev->stats.tx_aborted_errors); + return cnt; + } -void wanrouter_proc_cleanup (void) -{ - remove_proc_entry("config", proc_router); - remove_proc_entry("status", proc_router); - remove_proc_entry(ROUTER_NAME,proc_net); -} -/* - * Add directory entry for WAN device. - */ +#else /* ------------------- END OF LINUX 2.4.X VERSION -------------*/ -int wanrouter_proc_add (wan_device_t* wandev) -{ - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - - wandev->dent = create_proc_entry(wandev->name, 0, proc_router); - if (!wandev->dent) - return -ENOMEM; - wandev->dent->proc_fops = &wandev_fops; - wandev->dent->proc_iops = &router_inode; - wandev->dent->get_info = wandev_get_info; - wandev->dent->data = wandev; - return 0; -} -/* - * Delete directory entry for WAN device. - */ - -int wanrouter_proc_delete(wan_device_t* wandev) -{ - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - remove_proc_entry(wandev->name, proc_router); - return 0; -} -/****** Proc filesystem entry points ****************************************/ + /* Proc filesystem interface */ + static int router_proc_perms(struct inode *, int); +#ifdef LINUX_2_1 + static ssize_t router_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); +#else + static int router_proc_read( + struct inode* inode, struct file* file, char* buf, int count); + static int device_write( + struct inode* inode, struct file* file, const char* buf, int count); +#endif -/* - * Verify access rights. - */ + /* Methods for preparing data for reading proc entries */ + static int config_get_info(char* buf, char** start, off_t offs, int len, + int dummy); + static int status_get_info(char* buf, char** start, off_t offs, int len, + int dummy); + static int wandev_get_info(char* buf, char** start, off_t offs, int len, + int dummy); + + /* Miscellaneous */ + + /* + * Global Data + */ + + /* + * Names of the proc directory entries + */ + + static char name_root[] = ROUTER_NAME; + static char name_conf[] = "config"; + static char name_stat[] = "status"; + + /* + * Structures for interfacing with the /proc filesystem. + * Router creates its own directory /proc/net/router with the folowing + * entries: + * config device configuration + * status global device statistics + * <device> entry for each WAN device + */ + + /* + * Generic /proc/net/router/<file> file and inode operations + */ +#ifdef LINUX_2_1 + static struct file_operations router_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#else + static struct file_operations router_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#endif -static int router_proc_perms (struct inode* inode, int op) -{ - return 0; -} + static struct inode_operations router_inode = + { + &router_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* follow link */ + NULL, /* readlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms + }; + + /* + * /proc/net/router/<device> file and inode operations + */ + +#ifdef LINUX_2_1 + static struct file_operations wandev_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + wanrouter_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#else + static struct file_operations wandev_fops = + { + NULL, /* lseek */ + router_proc_read, /* read */ + device_write, /* write */ + NULL, /* readdir */ + NULL, /* select */ + wanrouter_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ + }; +#endif -/* - * Read router proc directory entry. - * This is universal routine for reading all entries in /proc/net/wanrouter - * directory. Each directory entry contains a pointer to the 'method' for - * preparing data for that entry. - * o verify arguments - * o allocate kernel buffer - * o call get_info() to prepare data - * o copy data to user space - * o release kernel buffer - * - * Return: number of bytes copied to user space (0, if no data) - * <0 error - */ + static struct inode_operations wandev_inode = + { + &wandev_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms + }; + + /* + * Proc filesystem derectory entries. + */ + + /* + * /proc/net/router + */ + + static struct proc_dir_entry proc_router = + { + 0, /* .low_ino */ + sizeof(name_root) - 1, /* .namelen */ + name_root, /* .name */ + 0555 | S_IFDIR, /* .mode */ + 2, /* .nlink */ + 0, /* .uid */ + 0, /* .gid */ + 0, /* .size */ + &proc_dir_inode_operations, /* .ops */ + NULL, /* .get_info */ + NULL, /* .fill_node */ + NULL, /* .next */ + NULL, /* .parent */ + NULL, /* .subdir */ + NULL, /* .data */ + }; + + /* + * /proc/net/router/config + */ + + static struct proc_dir_entry proc_router_conf = + { + 0, /* .low_ino */ + sizeof(name_conf) - 1, /* .namelen */ + name_conf, /* .name */ + 0444 | S_IFREG, /* .mode */ + 1, /* .nlink */ + 0, /* .uid */ + 0, /* .gid */ + 0, /* .size */ + &router_inode, /* .ops */ + &config_get_info, /* .get_info */ + NULL, /* .fill_node */ + NULL, /* .next */ + NULL, /* .parent */ + NULL, /* .subdir */ + NULL, /* .data */ + }; + + /* + * /proc/net/router/status + */ + + static struct proc_dir_entry proc_router_stat = + { + 0, /* .low_ino */ + sizeof(name_stat) - 1, /* .namelen */ + name_stat, /* .name */ + 0444 | S_IFREG, /* .mode */ + 1, /* .nlink */ + 0, /* .uid */ + 0, /* .gid */ + 0, /* .size */ + &router_inode, /* .ops */ + status_get_info, /* .get_info */ + NULL, /* .fill_node */ + NULL, /* .next */ + NULL, /* .parent */ + NULL, /* .subdir */ + NULL, /* .data */ + }; + + /* Strings */ + static char conf_hdr[] = + "Device name | port |IRQ|DMA| mem.addr |mem.size|" + "option1|option2|option3|option4\n"; + + static char stat_hdr[] = + "Device name |protocol|station|interface|clocking|baud rate| MTU |ndev" + "|link state\n"; + + + /* + * Interface functions + */ + + /* + * Initialize router proc interface. + */ + +#ifdef LINUX_2_1 + __initfunc(int wanrouter_proc_init (void)) + { + int err = proc_register(proc_net, &proc_router); + + if (!err) { + proc_register(&proc_router, &proc_router_conf); + proc_register(&proc_router, &proc_router_stat); + } + return err; + } +#else + int wanrouter_proc_init (void) + { + int err = proc_register_dynamic(&proc_net, &proc_router); + + if (!err) { + proc_register_dynamic(&proc_router, &proc_router_conf); + proc_register_dynamic(&proc_router, &proc_router_stat); + } + return err; + } +#endif -static ssize_t router_proc_read(struct file* file, char* buf, size_t count, - loff_t *ppos) -{ - struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry* dent; - char* page; - int pos, offs, len; + /* + * Clean up router proc interface. + */ + + void wanrouter_proc_cleanup (void) + { + proc_unregister(&proc_router, proc_router_conf.low_ino); + proc_unregister(&proc_router, proc_router_stat.low_ino); +#ifdef LINUX_2_1 + proc_unregister(proc_net, proc_router.low_ino); +#else + proc_unregister(&proc_net, proc_router.low_ino); +#endif + } - if (count <= 0) - return 0; - - dent = inode->u.generic_ip; - if ((dent == NULL) || (dent->get_info == NULL)) - return 0; + /* + * Add directory entry for WAN device. + */ + + int wanrouter_proc_add (wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; - page = kmalloc(PROC_BUFSZ, GFP_KERNEL); - if (page == NULL) - return -ENOBUFS; - - pos = dent->get_info(page, dent->data, 0, 0); - offs = file->f_pos; - if (offs < pos) { - len = min(pos - offs, count); - if(copy_to_user(buf, (page + offs), len)) { - len = -EFAULT; - goto out; - } - file->f_pos += len; - } - else - len = 0; -out: kfree(page); - return len; -} - -/* - * Prepare data for reading 'Config' entry. - * Return length of data. - */ + memset(&wandev->dent, 0, sizeof(wandev->dent)); + wandev->dent.namelen = strlen(wandev->name); + wandev->dent.name = wandev->name; + wandev->dent.mode = 0444 | S_IFREG; + wandev->dent.nlink = 1; + wandev->dent.ops = &wandev_inode; + wandev->dent.get_info = &wandev_get_info; + wandev->dent.data = wandev; +#ifdef LINUX_2_1 + return proc_register(&proc_router, &wandev->dent); +#else + return proc_register_dynamic(&proc_router, &wandev->dent); +#endif + } -static int config_get_info(char* buf, char** start, off_t offs, int len) -{ - int cnt = sizeof(conf_hdr) - 1; - wan_device_t* wandev; - strcpy(buf, conf_hdr); - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 120)); - wandev = wandev->next) { - if (wandev->state) cnt += sprintf(&buf[cnt], - "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", - wandev->name, - wandev->ioport, - wandev->irq, - wandev->dma, - wandev->maddr, - wandev->msize, - wandev->hw_opt[0], - wandev->hw_opt[1], - wandev->hw_opt[2], - wandev->hw_opt[3]); + /* + * Delete directory entry for WAN device. + */ + + int wanrouter_proc_delete(wan_device_t* wandev) + { + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + proc_unregister(&proc_router, wandev->dent.low_ino); + return 0; } - return cnt; -} + /****** Proc filesystem entry points ****************************************/ -/* - * Prepare data for reading 'Status' entry. - * Return length of data. - */ + /* + * Verify access rights. + */ -static int status_get_info(char* buf, char** start, off_t offs, int len) -{ - int cnt = 0; - wan_device_t* wandev; + static int router_proc_perms (struct inode* inode, int op) + { + return 0; + } - cnt += sprintf(&buf[cnt], "\nSTATUS FOR PORT 0\n\n"); - strcpy(&buf[cnt], stat_hdr); - cnt += sizeof(stat_hdr) - 1; - - for (wandev = router_devlist; - wandev && (cnt < (PROC_BUFSZ - 80)); - wandev = wandev->next) { - if (!wandev->state) continue; - cnt += sprintf(&buf[cnt], - "%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", - wandev->name, - wandev->station ? " DCE" : " DTE", - wandev->interface ? " V.35" : " RS-232", - wandev->clocking ? "internal" : "external", - wandev->bps, - wandev->mtu, - wandev->ndev); - - switch (wandev->state) { - - case WAN_UNCONFIGURED: - cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); - break; - - case WAN_DISCONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); - break; - - case WAN_CONNECTING: - cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); - break; - - case WAN_CONNECTED: - cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); - break; - - default: - cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); - break; + /* + * Read router proc directory entry. + * This is universal routine for reading all entries in /proc/net/wanrouter + * directory. Each directory entry contains a pointer to the 'method' for + * preparing data for that entry. + * o verify arguments + * o allocate kernel buffer + * o call get_info() to prepare data + * o copy data to user space + * o release kernel buffer + * + * Return: number of bytes copied to user space (0, if no data) + * <0 error + */ +#ifdef LINUX_2_1 + static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) + { + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int pos, offs, len; + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return 0; + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + + pos = dent->get_info(page, dent->data, 0, 0, 0); + offs = file->f_pos; + if (offs < pos) { + len = min(pos - offs, count); + if(copy_to_user(buf, (page + offs), len)) + return -EFAULT; + file->f_pos += len; } + else + len = 0; + kfree(page); + return len; } - return cnt; -} -/* - * Prepare data for reading <device> entry. - * Return length of data. - * - * On entry, the 'start' argument will contain a pointer to WAN device - * data space. - */ +#else + static int router_proc_read( + struct inode* inode, struct file* file, char* buf, int count) + { + struct proc_dir_entry* dent; + char* page; + int err, pos, offs, len; + + if (count <= 0) + return 0; + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return -ENODATA; + err = verify_area(VERIFY_WRITE, buf, count); + if (err) return err; + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOMEM; + + pos = dent->get_info(page, dent->data, 0, 0, 0); + offs = file->f_pos; + if (offs < pos) { + len = min(pos - offs, count); + memcpy_tofs((void*)buf, (void*)(page + offs), len); + file->f_pos += len; + } + else len = 0; + kfree(page); + return len; + } +#endif -static int wandev_get_info(char* buf, char** start, off_t offs, int len) -{ - wan_device_t* wandev = (void*)start; - int cnt = 0; - int rslt = 0; - if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) - return 0; - if (!wandev->state) - return sprintf(&buf[cnt], "device is not configured!\n"); + /* + * Prepare data for reading 'Config' entry. + * Return length of data. + */ + + static int config_get_info(char* buf, char** start, off_t offs, int len, + int dummy) + { + int cnt = sizeof(conf_hdr) - 1; + wan_device_t* wandev; + strcpy(buf, conf_hdr); + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 120)); + wandev = wandev->next) { + if (wandev->state) cnt += sprintf(&buf[cnt], + "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", + wandev->name, + wandev->ioport, + wandev->irq, + wandev->dma, + wandev->maddr, + wandev->msize, + wandev->hw_opt[0], + wandev->hw_opt[1], + wandev->hw_opt[2], + wandev->hw_opt[3]); + } - /* Update device statistics */ - if (wandev->update) { + return cnt; + } - rslt = wandev->update(wandev); - if(rslt) { - switch (rslt) { - case -EAGAIN: - return sprintf(&buf[cnt], "Device is busy!\n"); + /* + * Prepare data for reading 'Status' entry. + * Return length of data. + */ + + static int status_get_info(char* buf, char** start, off_t offs, int len, + int dummy) + { + int cnt = 0; + wan_device_t* wandev; + + //cnt += sprintf(&buf[cnt], "\nSTATUS:\n\n"); + strcpy(&buf[cnt], stat_hdr); + cnt += sizeof(stat_hdr) - 1; + + for (wandev = router_devlist; + wandev && (cnt < (PROC_BUFSZ - 80)); + wandev = wandev->next) { + if (!wandev->state) continue; + cnt += sprintf(&buf[cnt], + "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |", + wandev->name, + PROT_DECODE(wandev->config_id), + wandev->config_id == WANCONFIG_FR ? + (wandev->station ? " Node" : " CPE") : + (wandev->config_id == WANCONFIG_X25 ? + (wandev->station ? " DCE" : " DTE") : + (" N/A")), + wandev->interface ? " V.35" : " RS-232", + wandev->clocking ? "internal" : "external", + wandev->bps, + wandev->mtu, + wandev->ndev); + + switch (wandev->state) { + + case WAN_UNCONFIGURED: + cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured"); + break; + + case WAN_DISCONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected"); + break; + + case WAN_CONNECTING: + cnt += sprintf(&buf[cnt], "%-12s\n", "connecting"); + break; + + case WAN_CONNECTED: + cnt += sprintf(&buf[cnt], "%-12s\n", "connected"); + break; + + case WAN_FT1_READY: + cnt += sprintf(&buf[cnt], "%-12s\n", "ft1 ready"); + break; default: - return sprintf(&buf[cnt], - "Device is not configured!\n"); + cnt += sprintf(&buf[cnt], "%-12s\n", "invalid"); + break; } } + return cnt; } - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets received", wandev->stats.rx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total packets transmitted", wandev->stats.tx_packets); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes received", wandev->stats.rx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "total bytes transmitted", wandev->stats.tx_bytes); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "bad packets received", wandev->stats.rx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "packet transmit problems", wandev->stats.tx_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "received frames dropped", wandev->stats.rx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit frames dropped", wandev->stats.tx_dropped); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "multicast packets received", wandev->stats.multicast); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "transmit collisions", wandev->stats.collisions); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receive length errors", wandev->stats.rx_length_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver overrun errors", wandev->stats.rx_over_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "CRC errors", wandev->stats.rx_crc_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "frame format errors (aborts)", wandev->stats.rx_frame_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver fifo overrun", wandev->stats.rx_fifo_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "receiver missed packet", wandev->stats.rx_missed_errors); - cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, - "aborted frames transmitted", wandev->stats.tx_aborted_errors); - return cnt; -} + /* + * Prepare data for reading <device> entry. + * Return length of data. + * + * On entry, the 'start' argument will contain a pointer to WAN device + * data space. + */ + + static int wandev_get_info(char* buf, char** start, off_t offs, int len, + int dummy) + { + wan_device_t* wandev = (void*)start; + int cnt = 0; + int rslt = 0; + + if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) + return 0; + if (!wandev->state) + return sprintf(&buf[cnt], "Device is not configured!\n"); + + /* Update device statistics */ + if (wandev->update) { + + rslt = wandev->update(wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + return sprintf(&buf[cnt], "Device is busy!\n"); + + default: + return sprintf(&buf[cnt], + "Device is not configured!\n"); + } + } + } + + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets received", wandev->stats.rx_packets); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total packets transmitted", wandev->stats.tx_packets); +#ifdef LINUX_2_1 + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes received", wandev->stats.rx_bytes); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "total bytes transmitted", wandev->stats.tx_bytes); +#endif + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "bad packets received", wandev->stats.rx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "packet transmit problems", wandev->stats.tx_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "received frames dropped", wandev->stats.rx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit frames dropped", wandev->stats.tx_dropped); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "multicast packets received", wandev->stats.multicast); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "transmit collisions", wandev->stats.collisions); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receive length errors", wandev->stats.rx_length_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver overrun errors", wandev->stats.rx_over_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "frame format errors (aborts)", wandev->stats.rx_frame_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver fifo overrun", wandev->stats.rx_fifo_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "receiver missed packet", wandev->stats.rx_missed_errors); + cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT, + "aborted frames transmitted", wandev->stats.tx_aborted_errors); + + return cnt; + } + +#endif /* End of ifdef LINUX_2_4 */ + -/* - * End - */ - #else /* * No /proc - output stubs */ - -int __init wanrouter_proc_init(void) + +__initfunc(int wanrouter_proc_init(void)) { return 0; } @@ -436,6 +1055,33 @@ return 0; } +#endif + +/*============================================================================ + * Write WAN device ???. + * o Find WAN device associated with this node + */ +#ifdef LINUX_2_0 +static int device_write( + struct inode* inode, struct file* file, const char* buf, int count) +{ + int err = verify_area(VERIFY_READ, buf, count); + struct proc_dir_entry* dent; + wan_device_t* wandev; + + if (err) return err; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->data == NULL)) + return -ENODATA; + + wandev = dent->data; + + printk(KERN_ERR "%s: writing %d bytes to %s...\n", + name_root, count, dent->name); + + return 0; +} #endif /* diff -u --recursive --new-file v2.4.3/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.4.3/linux/net/x25/af_x25.c Mon Jan 22 13:32:10 2001 +++ linux/net/x25/af_x25.c Thu Apr 12 12:11:39 2001 @@ -409,6 +409,9 @@ len = min(len, sizeof(int)); + if (len < 0) + return -EINVAL; + if (put_user(len, optlen)) return -EFAULT; @@ -912,7 +915,7 @@ size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; - if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) + if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; X25_SKB_CB(skb)->flags = msg->msg_flags; @@ -1283,6 +1286,7 @@ sendmsg: x25_sendmsg, recvmsg: x25_recvmsg, mmap: sock_no_mmap, + sendpage: sock_no_sendpage, }; #include <linux/smp_lock.h> diff -u --recursive --new-file v2.4.3/linux/net/x25/x25_out.c linux/net/x25/x25_out.c --- v2.4.3/linux/net/x25/x25_out.c Wed Jan 24 15:28:36 2001 +++ linux/net/x25/x25_out.c Thu Apr 12 12:11:39 2001 @@ -79,7 +79,7 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, noblock, &err)) == NULL){ + if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, noblock, &err)) == NULL){ if(err == -EWOULDBLOCK && noblock){ kfree_skb(skb); return sent; diff -u --recursive --new-file v2.4.3/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c --- v2.4.3/linux/scripts/lxdialog/checklist.c Sun Feb 4 10:05:30 2001 +++ linux/scripts/lxdialog/checklist.c Fri Apr 6 10:42:55 2001 @@ -211,13 +211,15 @@ status[i+scroll], i, i == choice); } - wnoutrefresh (list); - print_arrows(dialog, choice, item_no, scroll, box_y, box_x + check_x + 5, list_height); print_buttons(dialog, height, width, 0); + wnoutrefresh (list); + wnoutrefresh (dialog); + doupdate (); + while (key != ESC) { key = wgetch (dialog); @@ -355,7 +357,11 @@ case ESC: break; } + + /* Now, update everything... */ + doupdate (); } + delwin (dialog); free (status); diff -u --recursive --new-file v2.4.3/linux/scripts/tkgen.c linux/scripts/tkgen.c --- v2.4.3/linux/scripts/tkgen.c Mon Jun 19 13:45:52 2000 +++ linux/scripts/tkgen.c Fri Apr 6 10:42:55 2001 @@ -155,7 +155,7 @@ printf("\"catch {focus $oldFocus}; " ); /* * We are checking which windows should be destroyed and which are - * common parrents with the next one. Remember that menu_num field + * common parents with the next one. Remember that menu_num field * in mainmenu_option record reports number of its *parent* menu. */ if ( menu_num < tot_menu_num diff -u --recursive --new-file v2.4.3/linux/scripts/ver_linux linux/scripts/ver_linux --- v2.4.3/linux/scripts/ver_linux Fri Mar 2 11:12:12 2001 +++ linux/scripts/ver_linux Thu Apr 12 12:16:36 2001 @@ -20,7 +20,9 @@ ld -v 2>&1 | awk -F\) '{print $1}' | awk \ '/BFD/{print "binutils ",$NF}' -mount --version | awk -F\- '{print "util-linux ", $NF}' +fdformat --version | awk -F\- '{print "util-linux ", $NF}' + +mount --version | awk -F\- '{print "mount ", $NF}' insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}'